Frage

Kennt jemand eine „Technik“ Speicherlecks durch intelligente Zeiger verursacht zu entdecken? Ich arbeite derzeit an einem großen Projekt geschrieben in C ++ , die stark intelligente Zeiger mit Referenzzählung verwendet. Offensichtlich haben wir einige Speicherlecks durch intelligente Zeiger verursacht, die noch irgendwo im Code referenziert werden, so dass ihr Gedächtnis nicht free'd bekommt. Es ist sehr schwer, die Codezeile mit der „unnötig“ Referenz zu finden, die das entsprechende Objekt verursacht nicht free'd werden (obwohl es nicht von ist verwenden mehr).

fand ich einige Ratschläge im Web, die Call-Stacks von den Aufwärts- / Abwärts Operationen des Referenzzählers zu sammeln vorgeschlagen. Das gibt mir einen guten Hinweis, den Teil des Codes des Referenzzähler verursacht hat, zu erhalten erhöht oder verringert wird.

Aber was ich brauche, ist eine Art von Algorithmus, die Gruppen der entsprechenden „Zunahme / Abnahme Call Stacks“ zusammen. Nach dieser Paare von Anruf Stapel entfernt wird, habe ich hoffentlich (mindestens) eine „Erhöhung Aufrufstapel“ übrig, die mir die Stück-Code mit dem „unnötig“ Referenz zeigt, dass das entsprechende Objekt verursacht nicht befreit werden. Jetzt wird es keine große Sache sein, um das Leck zu reparieren!

Aber hat jemand eine Idee für einen „Algorithmus“, der die Gruppierung das?

Die Entwicklung erfolgt unter Windows XP .

(Ich hoffe, jemand verstanden, was ich versuchte zu erklären, ...)

EDIt. Ich spreche von Lecks durch zirkuläre Referenzen verursacht

War es hilfreich?

Lösung

Beachten Sie, dass eine Quelle von Leckagen mit Referenzzählung Smart Pointer sind Zeiger mit Kreis Abhängigkeiten . Zum Beispiel hat A einen Smart-Zeiger auf B und B hat einen Smartpointer zu A. weder A noch B zerstört wird. Sie werden feststellen müssen, und dann die Abhängigkeiten brechen.

Wenn möglich, verwenden Sie intelligente Zeiger steigern, und verwenden Sie shared_ptr für Zeiger, die angeblich Eigentümer der Daten sein, und weak_ptr für Zeiger soll nicht löschen nennen.

Andere Tipps

So wie ich es tun, ist einfach: - auf jedem AddRef () -Eintrag Call-Stack, - passende Release () entfernt sie. Auf diese Weise am Ende des Programms mir ohne Bearbeitungs Releases mit AddRefs () links. Keine Notwendigkeit Paare passen,

Wenn Sie das Leck in einer deterministischen Art und Weise wiedergeben können, eine einfache Technik, die ich oft verwendet, ist alle Ihren Smart-Pointer in der Reihenfolge ihrer Konstruktion an der Nummer (einen statischen Zähler im Konstruktor verwenden), und melden Sie diese ID zusammen mit dem Leck . Dann das Programm erneut aus, und löst ein Debugbreak (), wenn der Smart-Pointer mit der gleichen ID aufgebaut wird.

Sie sollten auch dieses große Werkzeug betrachten: http: //www.codeproject.com/KB/applications/visualleakdetector.aspx

Um Referenzzyklen erkennen Sie eine grafische Darstellung aller Referenz-Objekte gezählt haben. Ein solcher Graph ist nicht leicht zu konstruieren, aber es kann getan werden.

Erstellen Sie eine globale set<CRefCounted*> registrieren Referenz gezählt Objekte leben. Dies ist einfacher, wenn Sie gemeinsam AddRef () Implementierung haben - nur this Zeiger auf den Satz hinzufügen, wenn Referenzzähler von 0 auf 1 geht Objekt Ebenso in Release () Objekt aus dem Satz entfernen, wenn es Referenzzähler von 1 auf 0 geht.

Als nächstes bietet eine Möglichkeit die Menge der referenzierten Objekte aus jeder CRefCounted* zu erhalten. Es könnte ein virtual set<CRefCounted*> CRefCounted::get_children() sein oder was auch immer zu Ihnen passt. Jetzt haben Sie einen Weg, um die Grafik zu gehen.

Schließlich implementieren Ihre Lieblings-Algorithmus für Zyklus-Erkennung in einem gerichteten Graphen . Starten Sie das Programm, einige Zyklen erstellen und Zyklusdetektor laufen. Genießen! :)

Was ich tue, ist der Smart-Pointer mit einer Klasse wickeln, die FUNCTION und LINE Parameter nehmen. Erhöht eine Zählung für diese Funktion und die Leitung jedes Mal, wenn der Konstruktor aufgerufen wird, und dekrementiert die Zählung jedes Mal, wenn der Destruktor aufgerufen wird. dann schreibe eine Funktion, die die Funktion / Line / zählen Informationen Dumps. Das sagt Ihnen, wo Sie alle Ihre Referenzen erstellt wurden

Was habe ich zu lösen dies getan, die außer Kraft zu setzen ist malloc / new & Frei / löschen Betreiber, so dass sie Spur in einer Datenstruktur, so viel wie möglich zu halten über die Operation Sie durchführen.

Zum Beispiel beim Überschreiben malloc / new können Sie eine Aufzeichnung der Adresse des Anrufers erstellen, die Menge des angeforderten Bytes, der zugeordnete Zeigerwert zurückgegeben und eine Sequenz-ID, so dass alle Ihre Aufzeichnungen sein sequenziert (ich weiß nicht, ob Sie mit Themen beschäftigen, aber Sie müssen das berücksichtigen, auch).

Beim Schreiben der Frei / löschen Routinen, halte ich auch den Überblick über die Adresse des Anrufers und die Zeiger Info. Dann suche ich nach hinten in der Liste, und versuchen, die malloc / neu anzupassen Pendant den Zeiger als mein Schlüssel. Wenn ich es nicht finden, wirft eine rote Fahne.

Wenn Sie es sich leisten können, können Sie in Ihren Daten die Sequenz ID einbetten absolut sicher zu sein, wer und wann Zuteilung Anruf getätigt wurde. Der Schlüssel hier ist, um jede Transaktion eindeutig zu identifizieren Paar so viel wie wir können.

Dann werden Sie eine dritte Routine haben Ihre Speicherzuordnungen / Deallokation Geschichte anzeigt, zusammen mit den Funktionen jede Transaktion aufgerufen wird. (Dies kann durch Parsen der symbolische Karte aus Ihrem Linker erreicht werden). Sie werden wissen, wie viel Speicher Sie jederzeit zugewiesen haben wird und wer es getan hat.

Wenn Sie nicht über genügend Ressourcen haben, diese Transaktionen (meinen typischen Fall für 8-Bit-Mikrocontroller) durchzuführen, können Sie Ausgabe der gleichen Informationen über eine serielle oder TCP-Verbindung zu einem anderen Computer mit genügend Ressourcen.

Es geht nicht darum, ein Leck zu finden. Im Fall von Smart-Pointer wird es höchstwahrscheinlich zu einem gewissen Gattungs Ort wie Create () leiten, die Tausende von Zeit genannt wird. Es ist eine Frage der Bestimmung, welche Stelle im Code nur knapp sein Ziel Anruf Release () auf ref gezählt Objekt.

Da sagen Sie, dass Sie mit Windows, können Sie in der Lage sein, die Vorteile von Microsofts User-Mode-Dump Heap-Dienstprogramm zu nehmen, UMDH , das kommt mit der Debugging tools für Windows . UMDH macht Schnappschüsse Ihrer Speichernutzung der Anwendung, die Aufzeichnung der Stapel für jede Zuordnung verwendet, und können Sie mehrere Schnappschüsse zu sehen, zu vergleichen, was der allocator ruft „durchgesickert“ Speicher. Er übersetzt auch den Stack-Traces zu Symbolen für Sie dbghelp.dll verwenden.

Es gibt auch eine andere Microsoft-Tool „LeakDiag“ genannt, die mehr Speicher als Zuweiser UMDH unterstützt, aber es ist ein bisschen schwieriger zu finden und scheint nicht aktiv gepflegt werden. Die neueste Version ist mindestens fünf Jahre alt, wenn ich mich recht erinnere.

Wenn ich Sie wäre, würde ich das Protokoll nehmen und eine schnelle Skript schreiben, etwas zu tun, wie die folgenden (Mine ist in Ruby):

def allocation?(line)
  # determine if this line is a log line indicating allocation/deallocation
end

def unique_stack(line)
  # return a string that is equal for pairs of allocation/deallocation
end

allocations = []
file = File.new "the-log.log"
file.each_line { |line|
  # custom function to determine if line is an alloc/dealloc
  if allocation? line
    # custom function to get unique stack trace where the return value
    # is the same for a alloc and dealloc
    allocations[allocations.length] = unique_stack line
  end
}

allocations.sort!

# go through and remove pairs of allocations that equal,
# ideally 1 will be remaining....
index = 0

while index < allocations.size - 1
  if allocations[index] == allocations[index + 1]
    allocations.delete_at index
  else
    index = index + 1
  end
end

allocations.each { |line|
  puts line
}

Diese im Grunde durch das Protokoll gehen und erfasst jede Zuordnung / Aufhebung der Zuordnung und speichern einen eindeutigen Wert für jedes Paar, dann sortieren und Paare, das Spiel zu entfernen, sehen, was noch übrig ist.

Update: Sorry für alle Vermittler Bearbeitungen (I versehentlich geschrieben, bevor ich fertig war)

Für Windows finden Sie unter:

MFC Speicher Leak Detection

Ich bin ein großer Fan von Heapchecker Google - es wird nicht fangen alle Lecks, aber es wird die meisten von ihnen. ( Tipp: . Ein Link es in alle Unittests)

Der erste Schritt könnte sein, zu wissen, welche Klasse ist undicht. Sobald Sie es kennen, können Sie feststellen, wer die Referenz nimmt zu: 1. legen einen Haltepunkt für den Konstruktor der Klasse, die von shared_ptr gewickelt ist. 2. Schritt in mit Debugger innerhalb Shared_ptr wenn seine die Referenzzähler zu erhöhen: siehe variable pn-> pi _-> use_count_ Nehmen Sie die Adresse dieser Variablen durch Auswertung des Ausdrucks (etwa wie folgt: & this-> pn-> pi_.use_count_), erhalten Sie eine Adresse 3. Geben Sie in Visual Studio-Debugger, gehen Sie zu Debug-> New Breakpoint-> New Data- Breakpoint- ... Geben Sie die Adresse der Variablen 4. Führen Sie das Programm. Ihr Programm wird jedes Mal stoppen, wenn ein Punkt in dem Code Erhöhen und Verringern des Referenzzählers. Dann müssen Sie prüfen, ob diejenigen passen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top