2009-03-01 6 views
7

Mein Programm, leider, hat ein Speicherleck irgendwo, aber ich werde verdammt sein, wenn ich weiß, was es ist.Strategien zum Aufspüren von Speicherlecks, wenn Sie alles falsch gemacht haben

Seine Aufgabe ist es, in einem Haufen von ~ 2MB-Dateien zu lesen, einige Parsing und String-Ersetzung durchzuführen, dann geben Sie sie in verschiedenen Formaten. 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 (jeweils in einem eigenen Thread, da ich ein Idiot bin), der auf ein Objekt wirkt, 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 nächsten Verarbeitungsobjektwarteschlange 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.

Antwort

11

Eine Technik, die ich versuchen würde, ist die systematische Verringerung 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.

+0

+1 Ich nenne das "binäre Suche", weil ich die Hälfte des Codes deaktivieren und testen, ob das Problem noch besteht. Wiederholen Sie mit der anderen Hälfte. Angenommen, ich bekomme konsistente Ergebnisse, kann ich jetzt die Hälfte der Hälfte, die das Problem enthält, deaktivieren, bis ich die Ursache isoliert habe. –

5

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

Aber ernsthaft. 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.

+0

+2 (wenn ich könnte). Link zum relevantesten Eintrag: http://blogs.msdn.com/tess/archive/2009/02/27/net-memory-leak-reader-email-are-you-really-leaking-net-memory.aspx – Richard

2

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

0
  1. Add-Code an den Konstruktor des unamanaged Objekt loggt sein, wenn es onstructed, und eine eindeutige ID sortieren. Verwenden Sie diese eindeutige ID, wenn das Objekt wieder zerstört wird, und Sie können am am wenigsten sagen, welche gehen in die Irre gehen.
  2. Grep den Code für jeden Ort, den Sie konstruieren ein neues Objekt; folgen Sie diesem Code-Pfad, um zu sehen, ob Sie eine passende destroy haben.
  3. Fügen Sie Verkettungszeiger zu den konstruierten Objekten hinzu, so dass Sie eine Verknüpfung zu dem Objekt vor und nach dem aktuellen aufgebaut haben. Dann kannst du sie später durchgehen.
  4. Hinzufügen von Referenzzählern.
  5. Ist ein "Debug-Malloc" verfügbar?
0

Das verwaltete Debuggen in SoS (Son Strike) in für das Aufspüren von verwalteten Speicher ‚Lecks‘ immens poweful ist, da sie sind definitions Erkennbar aus den gc Wurzeln.

Es wird in WinDbg oder Visual Studio arbeiten

Es ist gar nicht so einfach (obwohl es in vielerlei Hinsicht einfacher zu bedienen in WinDbg ist) in den Griff zu bekommen. Hier ist ein tutorial

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

0

Ich verwende den Profiler dotTrace 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 durchführt, mache ich einen Snapshot, führe dann ein paar 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 der Stelle ihrer Erstellung sehen und somit herausfinden, welche Instanzen nicht freigegeben werden.

0

Woher wissen Sie, 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 Collection erfasst werden.

+0

Ich warte, bis das Programm ein halbes Gigabyte Speicher verwendet. Dann bin ich mir ziemlich sicher. – Merus

+0

Das ist ein bisschen flink, also: Es gibt ein Szenario, in dem ich es so ausführen kann, dass es Daten einliest, analysiert und liest und es nur etwa 50MB verwendet. Das ist in Ordnung. Wenn ich andere Stufen hinzufüge, wird die Speicherbelegung aktiviert. – Merus

1

diese: http://www.red-gate.com/Products/ants_profiler/index.htm

Die Speicher- und Leistungsprofil sind genial. 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.

+0

Versuchte Ameisen und es war schrecklich. Es verlangsamte die Leistung zu einem Crawl, was es noch schwieriger machte, dem zu folgen, was vor sich ging. – Merus

+0

Jeder Profiler, den ich ausprobiert habe, hat die Leistung verlangsamt. Sie werden viel Zeit damit verbringen, nach möglichen Antworten zu suchen, es sei denn, Sie verwenden ein Werkzeug, und Sie werden wahrscheinlich etwas Einfaches übersehen. –

0

Wenn Ihr nicht verwalteten Objekt wirklich die Ursache des Lecks ist, möchten Sie vielleicht, um es AddMemoryPressure nennen, wenn es nicht verwalteten Speicher und RemoveMemoryPressure ordnet in Finalize/Dispose/wo immer es den nicht verwalteten Speicher freigibt. 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.

+0

streng genommen ist es weniger wahrscheinlich, eine Garbage Collection auszulösen. Es gibt Hinweise auf den zusätzlichen Speicherdruck, der das Objekt speziell für GC zum Ziel macht. – ShuggyCoUk

+0

Fühlen Sie sich frei, nur die Antwort zu bearbeiten, um korrekt zu sein, ohne mich zu zitieren. Ich werde nicht beleidigt sein und es macht die Antwort viel lesbarer. Ich kann den Kommentar immer löschen, wenn er fehl am Platz ist ... – ShuggyCoUk

+0

Ich versuche nur, Kredit zu geben, wo Kredit fällig ist. Aber ich stimme zu, dass es sonst besser lesbar ist. –

0

Seien Sie vorsichtig, wie Sie "leak" definieren. "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 sind nicht alle "Speicherlecks" durch "Speicher" Arten von Problemen 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 Speichernutzung ging erheblich zurück.

IIS wurde immer noch genauso häufig 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 der gesamte Heap der C-Laufzeitbibliothek geschrieben wurde. Da niemand nach nicht verwalteten Ausnahmen gesucht hat, hat dies niemand gesehen, bis ich mit AQtime einige Profile von Automated QA erstellt 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" ging weg.

0

Sie erwähnten, 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.

0

Die beste Speicherprofilierungswerkzeug für .Net, ist dies:

http://memprofiler.com

Auch während ich hier bin, ist die beste Performance Profiler für .NET ist dies:

http://www.yourkit.com/dotnet/download/index.jsp

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-Spielengine 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.

0

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

static unigned __int64 _foo_id = 0; 
foo::foo() 
{ 
    ++_foo_id; 
    if (_foo_id == MAGIC_BAD_ALLOC_ID) 
     DebugBreak(); 
    std::werr << L"foo::foo @ " << _foo_id << std::endl; 
} 
foo::~foo() 
{ 
    --_foo_id; 
    std::werr << L"foo::~foo @ " << _foo_id << std::endl; 
} 

Wenn Sie es neu erstellen können, auch nur einmal oder zweimal mit der gleichen Zuteilung id, dies können Sie sehen, was genau dann geschieht und dort (natürlich TLS/threading muss auch behandelt werden, wenn nötig, aber ich habe es aus Gründen der Klarheit weggelassen).

Verwandte Themen