Was sind die besten Methoden zum Erkennen von Speicherlecks in nicht verwaltetem C / C ++ - Code? Und Kodierungsrichtlinien zu vermeiden? (Als ob es so einfach wäre;)
Wir haben in der Vergangenheit ein bisschen albern vorgegangen: Wir haben ein Zählerinkrement für jeden Speicherzuweisungsaufruf und jedes Dekrement beim Freigeben. Am Ende des Programms sollte der Zählerwert Null sein.
Ich weiß, das ist kein guter Weg und es gibt ein paar Fänge. (Wenn Sie beispielsweise Speicher freigeben, der durch einen Plattform-API-Aufruf zugewiesen wurde, stimmt Ihre Zuordnungsanzahl nicht genau mit Ihrer Freigabeanzahl überein. Natürlich haben wir den Zähler erhöht, wenn wir API-Aufrufe aufrufen, die den zugewiesenen Speicher aufrufen.)
Ich erwarte Ihre Erfahrungen, Vorschläge und vielleicht einige Verweise auf Tools, die dies vereinfachen.
quelle
Antworten:
Wenn Ihr C / C ++ - Code auf * nix portierbar ist, sind einige Dinge besser als Valgrind .
quelle
Wenn Sie Visual Studio verwenden, bietet Microsoft einige nützliche Funktionen zum Erkennen und Debuggen von Speicherlecks.
Ich würde mit diesem Artikel beginnen: https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx
Hier ist die kurze Zusammenfassung dieser Artikel. Fügen Sie zunächst die folgenden Überschriften hinzu:
Dann müssen Sie dies aufrufen, wenn Ihr Programm beendet wird:
Wenn Ihr Programm nicht jedes Mal an derselben Stelle beendet wird, können Sie dies zu Beginn Ihres Programms aufrufen:
Wenn das Programm beendet wird, werden alle Zuweisungen, die nicht frei waren, im Ausgabefenster zusammen mit der Datei, in der sie zugewiesen wurden, und dem Auftreten der Zuweisung gedruckt.
Diese Strategie funktioniert für die meisten Programme. In bestimmten Fällen wird es jedoch schwierig oder unmöglich. Die Verwendung von Bibliotheken von Drittanbietern, die beim Start eine Initialisierung durchführen, kann dazu führen, dass andere Objekte im Speicherauszug angezeigt werden, und das Aufspüren Ihrer Lecks erschweren. Wenn eine Ihrer Klassen Mitglieder mit demselben Namen wie eine der Speicherzuweisungsroutinen (z. B. malloc) hat, verursachen die CRT-Debug-Makros Probleme.
In dem oben genannten MSDN-Link werden andere Techniken erläutert, die ebenfalls verwendet werden können.
quelle
In C ++: Verwenden Sie RAII. Intelligente Zeiger mögen
std::unique_ptr
,std::shared_ptr
,std::weak_ptr
sind deine Freunde.quelle
Als C ++ - Entwickler hier einige einfache Richtlinien:
Für die Erkennung von Speicherlecks persönlich habe ich immer den Visual Leak Detector verwendet und finde ihn sehr nützlich.
quelle
Ich benutze DevStudio seit viel zu vielen Jahren und es wundert mich immer wieder, wie viele Programmierer nicht über die Speicheranalyse-Tools Bescheid wissen, die in den Debug-Laufzeitbibliotheken verfügbar sind. Hier sind einige Links, mit denen Sie beginnen können:
Verfolgen von Heap-Zuweisungsanforderungen - insbesondere der Abschnitt zu eindeutigen Zuordnungsanforderungsnummern
_CrtSetDbgFlag
_CrtSetBreakAlloc
Wenn Sie DevStudio nicht verwenden, ist dies natürlich nicht besonders hilfreich.
quelle
Ich bin erstaunt, dass niemand DebugDiag für Windows erwähnt hat .
Es funktioniert bei Release-Builds und sogar beim Kunden.
(Sie müssen nur die PDBs Ihrer Release-Version behalten und DebugDiag für die Verwendung des öffentlichen Microsoft-Symbolservers konfigurieren.)
quelle
Visual Leak Detector ist ein sehr gutes Tool, obwohl es die Aufrufe von VC9-Laufzeiten (z. B. MSVCR90D.DLL) nicht unterstützt.
quelle
Microsoft VC ++ im Debug-Modus zeigt Speicherlecks an, obwohl nicht angezeigt wird, wo sich Ihre Lecks befinden.
Wenn Sie C ++ verwenden können Sie immer neue explizit vermeiden , mit: Sie haben
vector
,string
,auto_ptr
(pre C ++ 11, ersetzt durchunique_ptr
in C ++ 11),unique_ptr
(C ++ 11) undshared_ptr
(C ++ 11) in Ihrem Arsenal.Wenn new unvermeidbar ist, versuchen Sie, es in einem Konstruktor auszublenden (und löschen Sie es in einem Destruktor). Gleiches gilt für APIs von Drittanbietern.
quelle
Es gibt verschiedene Ersatz-"Malloc" -Bibliotheken, mit denen Sie am Ende eine Funktion aufrufen können. Sie informiert Sie über den gesamten nicht freigegebenen Speicher und in vielen Fällen darüber, wer ihn überhaupt mallociert (oder neu erstellt) hat .
quelle
Wenn Sie MS VC ++ verwenden, kann ich dieses kostenlose Tool aus dem Codeprojekt Leakfinder von Jochen Kalmbach nur empfehlen .
Sie fügen die Klasse einfach Ihrem Projekt hinzu und rufen auf
vor und nach dem Code, den Sie auf Lecks prüfen möchten.
Sobald Sie den Code erstellt und ausgeführt haben, bietet Jochen ein übersichtliches GUI-Tool, mit dem Sie die resultierende .xmlleaks-Datei laden und durch den Aufrufstapel navigieren können, in dem jedes Leck generiert wurde, um die fehlerhafte Codezeile aufzuspüren.
PurifyPlus von Rational (jetzt im Besitz von IBM) zeigt Lecks auf ähnliche Weise, aber ich finde, dass das Leckfinder-Tool tatsächlich einfacher zu verwenden ist, da der Bonus nicht mehrere tausend Dollar kostet!
quelle
Ich habe es selbst nie benutzt, aber meine C-Freunde sagen mir Purify .
quelle
Wenn Sie Visual Studio verwenden, lohnt es sich möglicherweise, sich Bounds Checker anzusehen . Es ist nicht kostenlos, aber es war unglaublich hilfreich, um Lecks in meinem Code zu finden. Es führt nicht nur zu Speicherlecks, sondern auch zu GDI-Ressourcenlecks, WinAPI-Verwendungsfehlern und anderen Dingen. Es zeigt Ihnen sogar, wo der durchgesickerte Speicher initialisiert wurde, was das Auffinden des Lecks erheblich erleichtert.
quelle
Ich denke, dass es keine einfache Antwort auf diese Frage gibt. Wie Sie sich dieser Lösung wirklich nähern, hängt von Ihren Anforderungen ab. Benötigen Sie eine plattformübergreifende Lösung? Verwenden Sie new / delete oder malloc / free (oder beides)? Suchen Sie wirklich nur nach "Lecks" oder möchten Sie einen besseren Schutz, z. B. das Erkennen von Pufferüberläufen (oder -unterläufen)?
Wenn Sie auf der Windows-Seite arbeiten, verfügen die MS-Debug-Laufzeitbibliotheken über einige grundlegende Debug-Erkennungsfunktionen. Wie bereits in einem anderen bereits erwähnt, können in Ihrer Quelle mehrere Wrapper enthalten sein, die bei der Lecksuche helfen. Wenn Sie ein Paket finden, das sowohl mit new / delete als auch mit malloc / free funktioniert, erhalten Sie offensichtlich mehr Flexibilität.
Ich weiß nicht genug über die Unix-Seite, um Hilfe zu leisten, obwohl andere dies auch getan haben.
Über die reine Lecksuche hinaus gibt es jedoch den Gedanken, Speicherbeschädigungen über Pufferüberläufe (oder -unterläufe) zu erkennen. Diese Art der Debug-Funktionalität ist meiner Meinung nach schwieriger als die einfache Lecksuche. Diese Art von System ist auch noch komplizierter, wenn Sie mit C ++ - Objekten arbeiten, da polymorhpische Klassen auf unterschiedliche Weise gelöscht werden können, was zu Schwierigkeiten bei der Bestimmung des wahren Basiszeigers führt, der gelöscht wird. Ich kenne kein gutes "freies" System, das einen angemessenen Schutz gegen Überläufe bietet. Wir haben ein System (plattformübergreifend) geschrieben und fanden es ziemlich herausfordernd.
quelle
Ich möchte etwas anbieten, das ich in der Vergangenheit manchmal verwendet habe: einen rudimentären Leckprüfer, der auf Quellenebene und ziemlich automatisch ist. Ich gebe das aus drei Gründen weg:
Vielleicht finden Sie es nützlich.
Obwohl es ein bisschen krufty ist, lasse ich mich nicht beschämen.
Obwohl es an einige Win32-Hooks gebunden ist, sollte dies leicht zu lindern sein.
Es gibt Dinge, bei denen Sie vorsichtig sein müssen, wenn Sie es verwenden: Tun Sie nichts, worauf Sie sich
new
im zugrunde liegenden Code stützen müssen. Achten Sie auf die Warnungen vor Fällen, die oben in der Datei leakcheck.cpp möglicherweise übersehen werden. Beachten Sie dies, wenn Sie sich umdrehen Bei (und Behebung von Problemen mit) dem Code, der Image-Dumps ausführt, können Sie eine große Datei generieren.Das Design soll es Ihnen ermöglichen, den Checker ein- und auszuschalten, ohne alles neu zu kompilieren, was den Header enthält. Fügen Sie die Datei leakcheck.h ein, in der Sie die Überprüfung verfolgen und einmal neu erstellen möchten. Kompilieren Sie anschließend die Datei leakcheck.cpp mit oder ohne LEAKCHECK # define'd und verknüpfen Sie sie erneut, um sie ein- und auszuschalten. Wenn Sie unleakcheck.h einschließen, wird es lokal in einer Datei deaktiviert. Es stehen zwei Makros zur Verfügung: Mit CLEARALLOCINFO () wird vermieden, dass dieselbe Datei und Zeile unangemessen gemeldet wird, wenn Sie den Zuweisungscode durchlaufen, der die Datei leakcheck.h nicht enthält. ALLOCFENCE () fügt nur eine Zeile in den generierten Bericht ein, ohne eine Zuordnung vorzunehmen.
Bitte beachten Sie auch hier, dass ich dies seit einiger Zeit nicht mehr verwendet habe und Sie möglicherweise ein wenig damit arbeiten müssen. Ich lasse es fallen, um die Idee zu veranschaulichen. Wenn sich herausstellt, dass genügend Interesse besteht, wäre ich bereit, ein Beispiel auszuarbeiten, den Code in diesem Prozess zu aktualisieren und den Inhalt der folgenden URL durch etwas Schöneres zu ersetzen, das eine anständige syntaxfarbene Auflistung enthält.
Sie finden es hier: http://www.cse.ucsd.edu/~tkammeye/leakcheck.html
quelle
Für Linux: Probieren Sie Google Perftools aus
Es gibt viele Tools, die eine ähnliche Zuweisung / freie Zählung durchführen, die Vorteile von Goolge Perftools:
quelle
Die beste Verteidigung gegen Lecks ist eine Programmstruktur, die den Einsatz von Malloc minimiert. Dies ist nicht nur aus Programmiersicht gut, sondern verbessert auch die Leistung und Wartbarkeit. Ich spreche nicht von der Verwendung anderer Dinge anstelle von Malloc, sondern von der Wiederverwendung von Objekten und der sehr expliziten Überwachung aller Objekte, die herumgereicht werden, anstatt sie willkürlich zuzuweisen, wie man es in Sprachen mit Müllsammlern oft gewohnt ist wie Java.
Zum Beispiel hat ein Programm, an dem ich arbeite, eine Reihe von Rahmenobjekten, die Bilddaten darstellen. Jedes Frame-Objekt verfügt über Unterdaten, die der Destruktor des Frames freigibt. Das Programm führt eine Liste aller zugewiesenen Frames und überprüft, wenn es einen neuen benötigt, eine Liste nicht verwendeter Frame-Objekte, um festzustellen, ob ein vorhandener Frame wiederverwendet werden kann, anstatt einen neuen zuzuweisen. Beim Herunterfahren durchläuft es nur die Liste und gibt alles frei.
quelle
Ich würde empfehlen, Memory Validator von Software Verify zu verwenden. Dieses Tool hat sich als unschätzbare Hilfe erwiesen, um Speicherlecks aufzuspüren und die Speicherverwaltung der Anwendungen zu verbessern, an denen ich arbeite.
Ein sehr vollständiges und schnelles Werkzeug.
quelle
Zählen Sie die Zuweisungen und Freigaben, indem Sie Ihre eigenen Syscall-Funktionen interpolieren, die die Anrufe aufzeichnen und den Anruf dann an die eigentliche Funktion weiterleiten?
Nur so können Sie Anrufe verfolgen, die von Code stammen, den Sie nicht geschrieben haben.
Schauen Sie sich die Manpage für ld.so an. Oder ld.so.1 auf einigen Systemen.
Wenn Sie auch Google LD_PRELOAD ausführen, finden Sie auf www.itworld.com einige interessante Artikel, in denen die Technik erläutert wird.
quelle
Zumindest für MS VC ++ verfügt die C Runtime-Bibliothek über mehrere Funktionen, die ich in der Vergangenheit als hilfreich empfunden habe. Überprüfen Sie die MSDN-Hilfe für die
_Crt*
Funktionen.quelle
Paul Nettles mmgr ist seit langem ein Lieblingswerkzeug von mir. Sie fügen mmgr.h in Ihre Quelldateien ein, definieren TEST_MEMORY und es wird eine Textdatei mit Speicherproblemen bereitgestellt, die während der Ausführung Ihrer App aufgetreten sind.
quelle
Allgemeine Codierungsrichtlinie:
quelle
Speicher-Debugging-Tools sind Gold wert, aber im Laufe der Jahre habe ich festgestellt, dass zwei einfache Ideen verwendet werden können, um zu verhindern, dass die meisten Speicher- / Ressourcenlecks überhaupt erst codiert werden.
Schreiben Sie den Freigabecode sofort nach dem Schreiben des Erfassungscodes für die Ressourcen, die Sie zuweisen möchten. Mit dieser Methode ist es schwieriger zu "vergessen" und zwingt in gewisser Weise dazu, ernsthaft über den Lebenszyklus von Ressourcen nachzudenken, die im Voraus verwendet werden, anstatt als Nebeneffekt.
Verwenden Sie return so sparring wie möglich. Was zugewiesen wird, sollte nach Möglichkeit nur an einem Ort freigegeben werden. Der bedingte Weg zwischen Ressourcenbeschaffung und Freigabe sollte so einfach und offensichtlich wie möglich gestaltet werden.
quelle
Ganz oben auf dieser Liste (als ich sie las) stand Valgrind. Valgrind ist hervorragend geeignet, wenn Sie das Leck auf einem Testsystem reproduzieren können. Ich habe es mit großem Erfolg benutzt.
Was ist, wenn Sie gerade bemerkt haben, dass das Produktionssystem gerade undicht ist und Sie keine Ahnung haben, wie Sie es im Test reproduzieren sollen? Einige Beweise dafür, was falsch ist, werden im Zustand dieses Produktionssystems erfasst, und es kann ausreichen, einen Einblick zu geben, wo das Problem liegt, damit Sie es reproduzieren können.
Hier kommt die Monte-Carlo-Probenahme ins Spiel. Lesen Sie den Blog-Artikel von Raymond Chen, „Die Methode des armen Mannes, Speicherlecks zu identifizieren“, und überprüfen Sie dann meine Implementierung (vorausgesetzt, Linux wurde nur auf x86 und x86-64 getestet).
http://github.com/tialaramex/leakdice/tree/master
quelle
Unter dem Betriebssystem von Motorola haben wir die Speicherzuweisungsbibliothek entführt, um alle Speicherzuordnungen zu überwachen. Es hat geholfen, viele Probleme mit der Speicherzuweisung zu finden. Da Vorbeugen besser ist als Aushärten, würde ich die Verwendung eines statischen Analysewerkzeugs wie Klockwork oder PC-Lint empfehlen
quelle
lint
. Es gibt viele spezifische Prüfungen für C ++, die afaik schienen nicht. Siehe den Link in der Antwort (den ich von Lint in PC-Lint umbenannt habe).Valgrind ist eine gute Option für Linux. Unter MacOS X können Sie die MallocDebug-Bibliothek aktivieren, die verschiedene Optionen zum Debuggen von Speicherzuordnungsproblemen bietet (siehe die Malloc-Manpage, der Abschnitt "UMWELT" enthält die relevanten Details). Das OS X SDK enthält auch ein Tool namens MallocDebug (normalerweise in / Developer / Applications / Performance Tools / installiert), mit dem Sie die Nutzung und Lecks überwachen können.
quelle
Erkennen:
Debug CRT
Vermeiden:
Intelligente Zeiger, Boehm GC
quelle
Ein netter Ersatz für Malloc, Calloc und Reallloc ist rmdebug, es ist ziemlich einfach zu bedienen. Valgrind ist viel schneller als Valgrind, sodass Sie Ihren Code ausführlich testen können. Natürlich hat es einige Nachteile. Wenn Sie ein Leck gefunden haben, müssen Sie wahrscheinlich immer noch Valgrind verwenden, um herauszufinden, wo das Leck auftritt, und Sie können nur Mallocs testen, die Sie direkt ausführen. Wenn eine Bibliothek leckt, weil Sie sie falsch verwenden, wird rmdebug sie nicht finden.
http://www.hexco.de/rmdebug/
quelle
Die meisten Speicherprofiler verlangsamen meine große komplexe Windows-Anwendung bis zu dem Punkt, an dem die Ergebnisse unbrauchbar sind. Es gibt ein Tool, das sich gut zum Auffinden von Lecks in meiner Anwendung eignet: UMDH - http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx
quelle
Mtrace scheint die standardmäßige integrierte Version für Linux zu sein. Die Schritte sind:
MALLOC_TRACE = / tmp / mtrace.dat
export MALLOC_TRACE;
Leckinformationen mit mtrace your_prog_exe_name /tmp/mtrace.dat
(Ich musste das mtrace perl-Skript zuerst auf meinem Fedora-System installieren , wobei yum glibc_utils installiert wurde. )
quelle