Strategien zum Aufspüren von Speicherlecks, wenn alles erledigt ist Falsch

7

Mein Programm hat leider irgendwo ein Speicherleck, aber ich werde verdammt sein, wenn ich weiß, was es ist.

Seine Aufgabe ist es, eine Menge ~ 2MB-Dateien einzulesen, Parsing und String-Ersetzung durchzuführen und sie dann in verschiedenen Formaten auszugeben. Das bedeutet natürlich eine Menge Strings, und so zeigt das Memory-Tracing, dass ich viele Strings habe, was genau das ist, was ich erwarten würde. Die Struktur des Programms besteht aus einer Reihe von Klassen (jede in ihrem eigenen Thread, weil ich ein Idiot bin), der auf ein Objekt einwirkt, das jede Datei im Speicher darstellt. (Jedes Objekt hat eine Eingabewarteschlange, die an beiden Enden eine Sperre verwendet. Während dies bedeutet, dass ich diese einfache Verarbeitung parallel ausführen muss, bedeutet dies auch, dass ich mehrere 2MB-Objekte im Speicher habe.) Die Struktur jedes Objekts wird durch ein Schemaobjekt definiert .

Meine Verarbeitungsklassen lösen Ereignisse aus, wenn sie ihre Verarbeitung ausgeführt haben, und übergeben einen Verweis auf das große Objekt, das alle meine Zeichenfolgen enthält, um es der Warteschlange des nächsten Verarbeitungsobjekts hinzuzufügen. Wenn das Ereignis durch einen Funktionsaufruf ersetzt wird, der zur Warteschlange hinzugefügt wird, wird das Leck nicht gestoppt. Eines der Ausgabeformate erfordert, dass ich ein nicht verwaltetes Objekt verwende. Das Implementieren von Dispose () für die Klasse stoppt das Leck nicht. Ich habe alle Verweise auf das Schemaobjekt durch einen Indexnamen ersetzt. Kein Würfel. Ich habe keine Ahnung, was das verursacht, und keine Ahnung, wo ich hinschauen soll. Der Speicher-Trace hilft nicht, da alles, was ich sehe, eine Menge von Strings ist, die erzeugt werden, und ich sehe nicht, wo die Referenzen im Speicher stecken bleiben.

Wir werden ziemlich aufgeben und an dieser Stelle zurückrollen, aber ich habe ein pathologisches Bedürfnis, genau zu wissen, wie ich das vermasselt habe. Ich weiß, dass Stack Overflow meinen Code nicht genau durchkämmen kann, aber welche Strategien können Sie vorschlagen, um dieses Leck nachzuverfolgen? Ich werde das wahrscheinlich zu meiner Zeit machen, also ist jeder Ansatz machbar.

    
Merus 01.03.2009, 23:06
quelle

13 Antworten

11

Eine Technik, die ich versuchen würde, ist die systematische Reduzierung der Menge an Code, die Sie benötigen, um das Problem zu demonstrieren, ohne dass das Problem verschwinden würde. Dies ist informell als "Teile und herrsche" bekannt und ist eine leistungsstarke Debugging-Technik. Sobald Sie ein kleines Beispiel haben, das das gleiche Problem zeigt, wird es viel einfacher für Sie zu verstehen sein. Vielleicht wird das Speicherproblem an diesem Punkt klarer werden.

    
Greg Hewgill 01.03.2009, 23:11
quelle
5

Es gibt nur eine Person, die Ihnen helfen kann. Der Name dieser Person ist Tess Ferrandez . (gedämpfte Stille)

Aber im Ernst. lese ihren Blog (der erste Artikel ist ziemlich relevant). Zu sehen, wie sie dieses Zeug debuggt, wird Ihnen einen tiefen Einblick geben, was mit Ihrem Problem passiert.

    
Dave Markle 01.03.2009 23:12
quelle
2

Ich mag den CLR Profiler von Microsoft. Es bietet einige großartige Werkzeuge, um den verwalteten Heap zu visualisieren und Lecks aufzuspüren.

    
Maurice Flanagan 01.03.2009 23:13
quelle
1

Holen Sie sich dies: Ссылка

Die Speicher- und Leistungsprofile sind großartig. Die Fähigkeit, tatsächlich richtige Zahlen zu sehen statt zu raten, macht die Optimierung sehr schnell. Ich habe es bei der Arbeit ein wenig genutzt, um den Speicherbedarf unserer Haupt-App zu reduzieren.

    
Jamie Penney 01.03.2009 23:19
quelle
0
  1. Fügen Sie dem Konstruktor des unamaged Objekt, um zu protokollieren, wenn es ist erstellt, und sortieren Sie eine eindeutige ID. Verwenden Sie diese eindeutige ID beim Objekt ist wieder zerstört, und Sie können bei zumindest sagen, welche gehen Irre.
  2. Überzeuge den Code für jeden Ort, an dem du bist konstruiere ein neues Objekt; Folge dem Code-Pfad, um zu sehen, ob Sie eine haben passender destroy.
  3. Fügen Sie dem Zeiger Verkettungszeiger hinzu konstruierte Objekte, so haben Sie eine Verbindung zum konstruierten Objekt vor und nach dem aktuellen. Dann kannst du sie später durchgehen.
  4. Referenzzähler hinzufügen.
  5. Ist ein "Debug-Malloc" verfügbar?
Charlie Martin 01.03.2009 23:13
quelle
0

Das verwaltete Debugging, das in SoS (Son of Strike) hinzugefügt wird, ist immens leistungsfähig für das Aufspüren managed memory 'leaks', da sie definitionsgemäß von den gc-Wurzeln aus zu finden sind.

Es wird in WinDbg oder Visual Studio funktionieren (obwohl es in vieler Hinsicht einfacher ist, in WinDbg zu verwenden)

Es ist gar nicht so einfach, sich damit auseinander zu setzen. Hier ist ein Tutorial

Ich würde die Empfehlung, Tess Fernandez Blog auch zu überprüfen.

    
ShuggyCoUk 01.03.2009 23:15
quelle
0

Ich verwende den dotTrace Profiler zum Aufspüren von Speicherlecks. Es ist viel mehr deterministisch als methodische Versuche und Fehler und Ergebnisse viel schneller.

Für alle Aktionen, die das System ausführt, mache ich einen Snapshot, führe dann einige Iterationen der Funktion durch und mache dann einen weiteren Snapshot. Wenn Sie beide vergleichen, werden Ihnen alle Objekte angezeigt, die dazwischen erstellt wurden, aber nicht freigegeben wurden. Sie können dann den Stapelrahmen an dem Punkt ihrer Erstellung sehen und somit herausfinden, welche Instanzen nicht freigegeben werden.

    
Drew Noakes 01.03.2009 23:15
quelle
0

Woher wissen Sie eigentlich, dass Sie tatsächlich ein Speicherleck haben?

Eine andere Sache: Sie schreiben, dass Ihre Verarbeitungsklassen Ereignisse verwenden. Wenn Sie einen Ereignishandler registriert haben, wird das Objekt, das das Ereignis besitzt, am Leben erhalten - d. H. Der GC kann es nicht sammeln. Stellen Sie sicher, dass Sie alle Ereignishandler abmelden, wenn Sie möchten, dass Ihre Objekte als Garbage Collected erfasst werden.

    
Jakob Christensen 01.03.2009 23:17
quelle
0

Sei vorsichtig, wie du "leak" definierst. "Verwendet mehr Speicher" oder "verwendet zu viel Speicher" ist nicht dasselbe wie "Speicherleck". Dies gilt insbesondere in einer Umgebung, in der keine Abfälle gesammelt werden. Es kann einfach sein, dass GC den benötigten zusätzlichen Speicher nicht benötigt. Achten Sie auch auf den Unterschied zwischen der Verwendung von virtuellem Speicher und physischem Speicher.

Schließlich werden nicht alle "Speicherlecks" durch "Speicher" verursacht. Mir wurde einmal gesagt (nicht gefragt), ein dringendes Speicherleck zu beheben, das dazu führte, dass IIS häufig neu gestartet wurde. In der Tat habe ich Profiling gemacht und festgestellt, dass ich eine Menge Strings durch die StringBuilder-Klasse verwendet habe. Ich habe einen Objektpool (aus einem MSDN-Artikel) für die StringBuilder implementiert, und die Speicherauslastung ging erheblich zurück.

IIS wurde genauso oft neu gestartet. Dies lag daran, dass kein Speicherleck vorhanden war. Stattdessen gab es nicht verwalteten Code, der als threadsicher galt, aber nicht war. Die Verwendung in einem Web-Service (mehrere Threads) führte dazu, dass es über den gesamten Heap der C-Laufzeitbibliothek geschrieben wurde. Da niemand nach nicht verwalteten Ausnahmen suchte, hat dies niemand gesehen, bis ich mit AQtime etwas Profiling von Automated QA gemacht habe. Es hat zufällig ein Ereignisfenster, in dem die Schmerzensschreie aus der C-Laufzeitbibliothek angezeigt wurden.

Platzierte Sperren um die Aufrufe des nicht verwalteten Codes, und das "Speicherleck" verschwand.

    
John Saunders 02.03.2009 00:35
quelle
0

Wenn Ihr nicht verwaltetes Objekt tatsächlich die Ursache des Lecks ist, möchten Sie möglicherweise AddMemoryPressure aufrufen, wenn nicht gemanagter Speicher zugewiesen wird und RemoveMemoryPressure in Finalize / Dispose /, wo immer der nicht verwaltete Speicher freigegeben wird . Dies wird dem GC einen besseren Überblick über die Situation geben, da es möglicherweise nicht erkennt, dass es notwendig ist, die Sammlung anderweitig zu planen.

    
Logan Capaldo 01.03.2009 23:35
quelle
0

Sie haben erwähnt, dass Sie Ereignisse verwenden. Entfernen Sie die Handler von diesen Ereignissen, wenn Sie mit Ihrem Objekt fertig sind? Ich habe festgestellt, dass "lose" Event-Handler eine Menge Speicherleck-Probleme verursachen, wenn Sie eine Reihe von Handlern hinzufügen, ohne sie zu entfernen, wenn Sie fertig sind.

    
Justin Drury 02.03.2009 15:02
quelle
0

Das beste Speicherprofilerstellungswerkzeug für .Net ist das:

Ссылка

Auch wenn ich hier bin, ist der beste Leistungsprofiler für .Net das:

Ссылка

Sie sind auch ein gutes Preis-Leistungs-Verhältnis, haben wenig Overhead und sind einfach zu bedienen. Jeder, der es ernst meint mit der .Net-Entwicklung, sollte beides als eine persönliche Investition betrachten und sofort kaufen. Beide haben eine kostenlose Testversion.

Ich arbeite an einer Echtzeit-Game-Engine mit über 700.000 Codezeilen, die in C # geschrieben wurden, und habe Hunderte von Stunden mit diesen beiden Tools verbracht. Ich habe das Sci Tech Produkt seit 2002 und YourKit! für die letzten drei Jahre. Obwohl ich einige der anderen ausprobiert habe, bin ich immer zu diesen zurückgekehrt.

IMHO, sie sind beide absolut brillant.

    
Christian Beaumont 02.03.2009 16:00
quelle
0

Ähnlich wie bei Charlie Martin können Sie so etwas tun:

%Vor%

Wenn Sie es einmal oder zweimal mit der gleichen Zuweisungs-ID neu erstellen können, können Sie sehen, was gerade passiert (natürlich muss auch TLS / Threading behandelt werden, aber ich bin gegangen) es für die Klarheit).

    
squeegee 27.01.2012 23:42
quelle

Tags und Links