Speicherleckerkennung in C ++ mit / ohne Visual Leak Detector

8

Ich möchte Speicherverluste meines C ++ Programms in Windows erkennen. Ich lese die Dokumentation auch auf MSDN über mermoy Lecksuche und ich habe auch angefangen, Visual Leak Detector zu verwenden.

Ich habe Zweifel an der Meldung der Lecks. Ich erwarte einen Dateinamen mit einer Zeilennummer, aber mir wird immer der folgende Text gemeldet. Es enthält alle Komponenten einer Leckbeschreibung (Blocktyp, Speicheradresse, Daten usw.). außer dem Dateinamen und der Zeilennummer.

Wenn es ein echtes Leck ist? Wenn ja, wissen Sie, warum die Datei / Zeile nicht gemeldet wird? In der Zwischenzeit schaue ich auch auf diese URL

Danke

%Vor%     
user311906 25.08.2010, 09:45
quelle

7 Antworten

7

Ich habe verschiedene Methoden untersucht, um Speicherlecks zu verfolgen. Sie alle haben ihre Vorteile, aber auch ihre Nachteile.

Um ihre Vor- und Nachteile zu verstehen, müssen wir die verschiedenen Mechanismen und Anforderungen verstehen:

  1. Wie werden neu, löschen, malloc und frei abgefangen? Einige Tools verwenden #define, um neu zu definieren, delete, malloc und free, aber dies hängt von der richtigen Reihenfolge der Include-Dateien ab und kann Probleme verursachen, wenn eine Klasse z. eine Methode namens free (wie in Qt). Der Präprozessor wird diese Methode ebenfalls neu definieren, was zu Kompilierungsfehlern oder ungelösten externen Fehlern führen kann.

    Eine andere Möglichkeit besteht darin, die globalen Neu- und Löschoperatoren zu überschreiben. Dies ist eine viel sauberere Lösung, aber es schlägt fehl, wenn Sie eine Bibliothek von Drittanbietern haben, die eine neue in die Bibliothek stellt, aber das Löschen in der Kopfzeile (oder umgekehrt).

  2. Wie wird die Quelle des Anrufs ermittelt? Wenn new, delete, ... mit # define's abgefangen werden, werden oft die Präprozessorsymbole __FILE__ und __LINE__ verwendet, um die Quelle des Lecks zu erhalten. Wenn Sie in Ihrem Code jedoch "generische" Funktionen wie z. CreateString (), dann werden die meisten Lecks in diesen generischen Funktionen gemeldet, was Ihnen nicht wirklich hilft.

    Alternativ können Sie den Aufrufstapel zur Laufzeit abrufen. Es kann recht einfach mit der Windows StackWalk-Funktion durchgeführt werden, aber meiner Erfahrung nach ist das sehr sehr langsam. Eine viel schnellere Alternative besteht darin, den Basiszeiger direkt zu holen und sich auf die Stack-Frame-Pointer zu verlassen (Sie müssen mit / Oy kompilieren, um die Stack-Frame-Pointer zu erhalten). Sie können den Rahmen (Basis) Zeiger wie folgt erhalten: _asm mov DWORD PTR [FramePtr], ebp . Dann einfach schleifen und in der Schleife den Befehlszeiger von ((ADDR *)FramePtr)[1]; und den nächsten Rahmenzeiger von FramePtr = ((ADDR *)FramePtr)[0];

    holen
  3. Wie melden Sie die Lecks genau im Moment? In meinem Fall möchte ich, dass die Lecks am Ende der Anwendung gemeldet werden. Um dies jedoch zu ermöglichen, benötigen Sie am Ende Ihrer Anwendung einen Mechanismus zur Meldung von Lecks. Dies bedeutet, dass Sie, wenn Sie Ihre Lecks selbst melden möchten, darauf angewiesen sind, dass globale Variablen am Ende Ihrer Anwendung zerstört werden (und die Lecks in diesem Destruktor der globalen Variablen melden). Bei serverartigen Anwendungen sind Sie wahrscheinlich eher daran interessiert, die Speicherbelegung zwischen zwei Zeitpunkten zu unterscheiden.

Und jetzt die verschiedenen Lecksysteme:

  1. C RunTime: Meldet Lecks am Ende, hat aber keine anständige Möglichkeit, Anruflisten zu melden. Die Methode zum Abfangen von Aufrufen auf new, delete, ... kann Probleme bei Kombinationen mit Bibliotheken von Drittanbietern (wie Qt, Boost, ...) verursachen.

  2. Externe Microsoft-Dienstprogramme (wie GFlags, UMDH ,, ...): Sie scheinen nur Unterschiede zwischen zwei Zeitpunkten zu protokollieren. Der Aufruf-Stack scheint jedoch viel besser zu sein, obwohl das GFlags-Dienstprogramm Flags im Betriebssystem festlegen kann, die eine ernsthafte Verlangsamung Ihrer Anwendung verursachen können.

  3. Sichtlecksuchgerät. Scheint, alle Lecks richtig zu finden, aber in meinem Fall funktioniert es nicht, da ich eine 3rd-Party-DLL habe, die einfach den Prozess bei seinem DllUnload abbricht (scheint ein Windows 7-spezifisches Problem zu sein).

  4. Mein persönlicher Favorit (und die Leute werden mir nicht zustimmen, da bin ich mir sicher) ist es, einen eigenen Speichermanager zu schreiben. Das Abfangen kann leicht mit den globalen Operatoren "new" und "delete" erfolgen (mit den oben genannten möglichen Problemen), und Sie können den Aufruf-Stack wie oben beschrieben erhalten. Diese Alternative beruht auch darauf, einen Code zu haben, der im allerletzten Moment in Ihrer Anwendung ausgeführt wird.

Bei der Auswahl einer Alternative fand ich folgende Aspekte sehr wichtig für meine Situation:

  • Ich möchte, dass es in meiner Anwendung reibungslos funktioniert, so dass jeder Entwickler sofort informiert wird, wenn es ein Leck gibt. Wenn Sie die Lecksuche zu einem späteren Zeitpunkt verzögern, an dem Sie externe Dienstprogramme wie Purify verwenden, ist die Lecksuche viel schwieriger.
  • Ich möchte, dass Lecks automatisch am Ende der Anwendung gemeldet werden.
  • Ich möchte so viel wie möglich Informationen aus dem Leck (die Daten, die Aufrufliste, ...)

Hoffe, das hilft.

    
Patrick 25.08.2010 11:26
quelle
5

Dies ist die Ausgabe von Visual Studio eigenen Debug CRT, nicht die Ausgabe von Visual Leak Detector. Stellen Sie zunächst sicher, dass Sie die aktuelle Version unter Codeplex verwenden und dass Sie vld.h in Ihrem Projekt enthalten haben. Sie erhalten eine viel informativere Ausgabe.

    
the_mandrill 25.08.2010 10:34
quelle
2

Ok. Ich habe es nach dem Debuggen vieler Header-Dateien.

Hier ist, was getan werden muss, um Datei / Zeilennummer in der Ausgabe

zu aktivieren

"# define _CRTDBG_MAP_ALLOC"

"# define _CRTDBG_MAP_ALLOC_NEW"

    
Chubsdad 25.08.2010 13:24
quelle
1

Haben Sie mit Debug-Informationen kompiliert und sichergestellt, dass die pdb-Datei vom Lecksucher verfügbar ist? Ohne diese Informationen wäre es nicht möglich, Zeilennummern anzugeben.

    
Mark B 25.08.2010 13:31
quelle
0

Sie sollten Valgrind verwenden, es ist sehr mächtig und erklärt genau, wo die Lecks in Ihrem Programm sind. Ihr Programm muss möglicherweise mit gcc kompiliert werden, obwohl ...

    
Guillaume Lebourgeois 25.08.2010 09:57
quelle
0

Rational Purify ist als kostenpflichtiges Plugin für VC ++ erhältlich und ist sehr gut Leck (und andere Probleme) Detektor. Ich habe es oft unter Solaris verwendet, und es war sehr einfach zu verwenden und zu löschen. Ich habe auch von anderen Leuten gute Dinge über die Version für die Verwendung mit Visual Studio gehört, aber das habe ich noch nie probiert.

FWIW, ich vermute, dass Purify die Inspiration für Valgrind war, was bereits erwähnt wurde.

    
Donal Fellows 25.08.2010 10:44
quelle
0

Wenn die Zuordnungsnummern (die in den gewellten Klammern) immer gleich sind, Das könnte helfen . Im Grunde wurde beschrieben, wie VC ++ einen Haltepunkt generieren kann, wenn die Zuweisung mit der angegebenen Nummer versucht wird.

    
Björn Pollex 25.08.2010 10:58
quelle