2016-12-09 3 views
0

Ich habe den Speicherstream verwendet, um die Datei herunterzuladen. Sobald die Datei heruntergeladen wurde, muss ich den gesamten von diesem Speicherstrom belegten Speicher löschen.Sauberer Speicher wird verwendet

// Eine Datei entschlüsseln und im Speicherstream speichern.

public MemoryStream DecryptAndStoreInMemory(string inputFilePath, string userFileName) 
{ 
    MemoryStream msOutput = null; 
    if (File.Exists(inputFilePath)) 
    { 
     try 
     { 
      using (Aes encryptor = Aes.Create()) 
      { 
       Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(_password, _salt); 
       encryptor.Key = pdb.GetBytes(32); 
       encryptor.IV = pdb.GetBytes(16); 
       using (FileStream fsInput = new FileStream(inputFilePath, FileMode.Open)) 
       { 
        using (CryptoStream cs = new CryptoStream(fsInput, encryptor.CreateDecryptor(), CryptoStreamMode.Read)) 
        { 
         using (msOutput = new MemoryStream()) 
         { 
          int data; 
          while ((data = cs.ReadByte()) != -1) 
          { 
           msOutput.WriteByte((byte)data); 
          } 
         } 
        } 
       } 
      } 
      return msOutput; 
     } 
     catch (CryptographicException) 
     { 
      throw new Exception("Sorry we can not serve " + userFileName + " file at this time."); 
     } 
     catch (Exception) 
     { 
      throw; 
     } 
    } 
    else 
    { 
     throw new Exception("Sorry we could not locate " + userFileName); 
    } 

} 

Nachdem die Datei zur Antwort gesendet wurde, wird der Speicher nicht freigegeben. Es dauerte fast doppelt so groß wie die Datei. 17 MB Datei benötigt fast 40 MB Speicher.

Was sollte getan werden, um diesen Raum freizugeben. Ich habe versucht, Byte-Array zu löschen, aber festgestellt, dass es nur jedes Element des Arrays mit 0 ersetzt behält seine Länge gleich.

+3

Die erste Verteidigungslinie ist der Garbage Collector. Wenn die Variable "bytesInStream" nirgends mehr referenziert wird, sollte sie gesammelt und der Speicher freigegeben werden. Das setzt auch voraus, dass "BytesInStream" der eigentliche Unruhestifter ist. Können Sie versuchen, 'GC.Collect();' und 'GC.WaitForPendingFinalizers();'? Wird der Speicherverbrauch bei der Speicherprofilerstellung besser, wenn Sie ein wenig warten? –

+0

@MaximilianGerhardt Ich habe GC.Collect() oben und unten geschrieben, was zur Folge hat, dass der Speicher bei der nächsten Anfrage für die gleiche Datei bereinigt wird. Wenn ich die gleiche Datei erneut anfordere, dann wird der Speicher frei, der zuvor verwendet wurde, und wieder reservieren Sie den Speicher –

Antwort

1

Im .NET framwerk haben Sie keine direkte Kontrolle über die Speichernutzung. Ihr Speicher wird vom Garbage Collector (GC) gesteuert. Wenn Sie Ihren Stream entsorgt haben und dieser schließlich dereferenziert wird, heißt er tot. Das bedeutet, dass die Garbage-Collection automatisch ausgeführt wird, wenn der Speicherdruck zu hoch wird.

In der überwiegenden Mehrzahl der Fälle ist hier keine Optimierung erforderlich, da Speicher nicht benötigt wird, weil er nicht während der Garbage Collection freigegeben werden kann. Verwalteter Speicher mit einem GC ist auch nicht langsamer als nicht verwalteter Speicher, da die Zuweisung neuer Objekte im verwalteten Speicher im Vergleich zu nicht verwaltetem Speicher schnell ist (wenn genügend Arbeitsspeicher verfügbar ist), da verwalteter Speicher nicht fragmentiert ist.

Sie können Garbage Collection mit GC.Collect() initiieren, aber das könnte Ihren Code weniger performant als automatische Garbage Collection ausführen. Wenn Sie eine Sammlung initiieren, wird die verwendete Speichergröße nicht unbedingt verringert, da der GC nicht immer den freigegebenen Arbeitsspeicher an das Betriebssystem zurückgibt.

+0

Vielen Dank für die Informationen. Obwohl .NET Framework automatisch Speicher frei macht, habe ich Probleme mit der Leistung anderer auf dem Server gehosteter Anwendungen. Ich kam zu wissen, meine obige Logik ist der Hauptschuldige dafür und ich muss das Ding irgendwie wie reparieren. –

2

Um doppelte Pufferung zu vermeiden, rufen Sie nicht .ToArray(); stattdessen können Sie über ms.GetBuffer() auf den vorhandenen Puffer zugreifen. Beachten Sie, dass diese sperrig, so dass Sie vermutlich verwenden müssen:

context.Response.BinaryWrite(ms.GetBuffer(), 0, ms.Length); 

Beachten Sie, dass Sie nicht deterministisch ein Array kann sagen, gehen weg, und Array.Clear haben nicht den gewünschten Effekt. Cleanup ist die Aufgabe des Garbage Collectors, mit dem man sich normalerweise nicht anlegen sollte.


Jedoch! Ein besserer Ansatz ist es, nicht alles auf einmal zu lesen, sondern: einen reinen Streaming-Ansatz zu verwenden. Ich weiß nicht, wie deine DecryptAndStoreInMemory implementiert ist, also kann ich nicht sagen, ob das in deinem Fall möglich ist, aber: es ist normalerweise so.

+0

Ich habe meine Frage bearbeitet und 'DecryptAndStoreInMemory' hinzugefügt Methode Bitte schauen Sie und lassen Sie uns über zukünftige Erweiterungen wissen. –

+0

und in Bezug auf oben 'context.Response.BinaryWrite (ms.GetBuffer(), 0, ms.Length);' Ich bekomme nicht 'BinaryWrite' Methode mit 3 Eingabeparameter. Ich habe nur einen, der 'byte []' braucht. –

Verwandte Themen