Ich habe kürzlich den Besitz eines WCF-Windows-Dienstes übernommen, der die folgende statische Dienstprogrammklasse zum Abrufen von Suchdaten stark nutzt:
%Vor%Wie Sie sehen können, verwendet die statische ErrorData-Eigenschaft ein privates Unterstützungsfeld. ErrorData ist ein Dictionary, das mit einer XML-Ressource im Dateisystem erstellt wird, weshalb der Inhalt der Datei beim ersten Abruf in HttpRuntime.Cache gespeichert wird.
Bei normaler Auslastung verbraucht der Dienst etwa 120 MB RAM.
Irgendwann hatte ein Teammitglied das Bedürfnis, eine weitere Optimierungsebene einzuführen, indem eine statische Eigenschaft erstellt wurde, die von einem lazy-luden statischen Feld unterstützt wurde. Wie auch immer, das Vorhandensein dieses statischen Feldes verursacht nach nur wenigen Aufrufen des Dienstes einen ziemlich schweren Speicherverlust (500 MB +).
Sobald ich das statische Feld und die Eigenschaft entferne (Clients rufen stattdessen Utility.GetErrorData () auf), wird der Speicherverbrauch wieder auf normale Werte zurückgesetzt.
Kann jemand erklären, warum das Vorhandensein dieses statischen Feldes ein Speicherleck verursacht? Der WCF-Dienst wird mit InstanceContextMode.PerCall ausgeführt, wenn dies einen Unterschied macht.
Vielen Dank.
Wenn die Fehlerdatei sehr groß ist, lädt die statische Version das riesige XML-Dokument in den Speicher und gibt es nie wieder frei. Wenn Clients zuvor GetErrorData () aufgerufen hatten, wurden die Daten zuvor in den Speicher geladen und zurückgegeben, wodurch Speicher gelöscht wurde.
Es gibt keine Synchronisation. Wenn also die statische Variable nicht geladen wurde, hätten mehrere gleichzeitige Anfragen begonnen, das Fehlerdokument separat zu laden. Nur ein Dictionary würde gewinnen und in der statischen Variable gespeichert werden. Wenn die Fehlerdatei jedoch groß ist, erhöhen mehrere Threads, die sie gleichzeitig laden, den Speicherdruck. Wenn dies der Fall wäre, würde ich erwarten, dass die nächste Speicherbereinigung die zusätzlichen Instanzen zurückgewinnen und viel von diesem Speicher freigeben würde.
Beachten Sie auch, dass die statische Instanzversion die Fehlerdatei einmal lädt. Wenn also zusätzliche Fehler erzeugt werden, werden diese niemals an den Client zurückgegeben.
Ich bin mir nicht ganz sicher, welche Codeänderung Sie meinen, wenn Sie über die Änderung sprechen. Nach dem Lesen des Codes ist es jedoch wahrscheinlich, dass Sie GetErrorData mehr als einmal aufrufen, und das Wörterbuch füllt sich mit vielen doppelten Einträgen. Wenn Sie Protokollierungscode hinzufügen, welcher Code wird wiederholt angezeigt?
Martyn
Versuchen Sie, einen Auszug aus Ihrem w3p-Prozess zu erstellen, und prüfen Sie, was auf dem Heap für große Objekte vorhanden ist und welche Objekte einen großen Speicherblock belegen. Das wird Ihnen helfen, die genaue Ursache für Speicherverlust zu erreichen.
Sie sollten auch die im Speicher geladenen Baugruppen überprüfen. XMLserializers ist eines der Beispiele.
Siehe Tess Blog über Speicherlecks. Ссылка
Macht das Hinzufügen von Synchronisation Ihr "Speicherleck" zu beheben?
Das heißt, machen Sie zum Beispiel LoadXmlDocument () und GetErrorData () beide privat und modifizieren Sie die ErrorData-Eigenschaft in etwa so
%Vor%Hinweis: In der Regel bedeutet ein Speicherverlust, dass die Anwendung im Laufe der Zeit immer mehr Speicher verbraucht (der nie zurückgewonnen wird). Ist dies das, was Sie beobachten, oder wird Ihr Speicherverbrauch einfach höher, wenngleich stabil, wenn Sie die Implementierung ändern? Um wirklich zu überprüfen, dass Sie tatsächlich ein Speicherleck haben und was die eigentliche Ursache ist (welche Objekte können nicht gesammelt / finalisiert werden), müssen Sie oft einen Speicherprofiler verwenden.
Tags und Links wcf memory-leaks debugging static