2009-04-11 12 views
2

Ich habe in einigen meiner Anwendungen und auch in DLLs, die alle von einer IRefCounted-Schnittstelle erben und implementieren, eine Anzahl von Referenzzählklassen.C++: Debugging von Speicherlecks im Referenzzählsystem

Um bei der Suche nach der Quelle dieser Speicherverluste zu helfen, möchte ich, dass jede Anwendung eine Liste aller dieser reference gezählten Klassen führt.

Das Problem ist die Verwaltung von Instanzen dieser Listen, so dass ihre Verwendung die Verwendung meiner Klassen nicht beeinflusst (z. B. muss ich nicht ständig einen Zeiger auf eine Liste übergeben, sondern irgendwie anhängen der Prozess).

- Es besteht eine gute Chance, dass mehrere dieser Anwendungen gleichzeitig ausgeführt werden und dieselbe DLL verwenden. Jede Anwendung benötigt eine eigene Objektliste, und alle DLLs, die von dieser Anwendung geladen werden, müssen diese Liste verwenden (aber beachten Sie, dass eine DLL von mehreren Anwendungen geladen werden kann ...).
-Die Liste muss nach jeder anderen globalen und statischen Variablen in der Anwendung zerstört werden, so dass die Objekte, die in der Liste verbleiben, wenn sie zerstört werden, diejenigen sind, die nicht korrekt freigegeben wurden.

Ich werde dann einfach einen Haltepunkt zum Destruktor der Liste hinzufügen, damit ich durch alle nicht zugeordneten Objekte im Debugger schauen kann.

+0

Entschuldigung, was ist Ihre Frage? –

Antwort

1

Ich schätze, Sie verwenden COM. Sie müssen wahrscheinlich einen Weg finden, eine weak pointer zu haben, so dass die Registrierung von instanziierten Objekten nicht verhindert, dass sie zerstört werden.

Wenn Sie alle Klassen ändern können, können Sie ein statisches Member injizieren, um alle Instanzen zu verfolgen und den Destruktor einer Instanz aus dem statischen Member zu entfernen. Zum Beispiel könnten Sie eine Basisklasse oder Utility-Klasse wie folgt verwenden:

class InstanceRegistry { 
protected: 
    InstanceRegistry() { 
     registry.insert(this); 
    } 
    ~InstanceRegistry() { 
     registry.remove(this); 
    } 
private: 
    static SomeContainerType<InstanceRegistry*> registry; 
}; 

zusätzliche Arbeit getan werden müßte, wenn Sie einen anderen Registry für verschiedene Arten von Klassen wollen usw.

+0

Ich benutze nicht COM, und ich könnte etwas zum con/destructor der Objekte hinzufügen hinzufügen, um sie aus der Liste zu entfernen. Die Listenprobs sollten nicht auf die Objekte verweisen. –

+0

COM verwendet IUnknown, nicht IRefCounted. –

+0

Danke. Die COM-Notiz wurde gestrichen. –

1

Wenn Prozesse verwenden dieselbe DLL, erhält jeder Prozess seine eigene private Kopie der statischen (oder "globalen") Daten dieser DLL.

Also alles, was Sie tun müssen, ist die Liste eine globale Variable in einer DLL zu machen, und verknüpfen Sie diese DLL von jeder Anwendung. Auf diese Weise müssen Sie nichts Zusätzliches weitergeben.

Ihre Idee, die Zerstörung der Liste einzufangen, ist aufgrund der Unvorhersagbarkeit der Reihenfolge der Zerstörung von Objekten in einem Multi-DLL-Prozess mit Schwierigkeiten behaftet.

Es wäre viel einfacher, den Inhalt der Liste am Ende Ihrer main oder WinMain Funktion auszugeben.

Wenn Sie keine intelligente Zeigerklasse konsistent verwenden, tun Sie dies. Es kann sich auch lohnen, nach zyklischen Referenzzählungen zu suchen - Objekt A zählt auf Objekt B und umgekehrt. Dies ist eine häufige Ursache für unveröffentlichte Objekte.

Update:

Um alle statischen Destruktoren zu zwingen, Objekte zu laufen und lassen, so können Sie dann die Einträge in der Liste prüfen, danach müssen Sie Ihre Anwendung eine bestimmte Art und Weise strukturieren.

Angenommen, Sie haben eine sehr minimale EXE, die den Prozess startet, und lädt eine Reihe anderer DLLs, die tatsächlich die ganze Arbeit erledigen. Diese anderen DLLs werden irgendwie mit LoadLibrary geladen (vielleicht von COM oder einem COM-ähnlichen System). Die LoadLibrary-API funktioniert entweder durch Laden der DLL in den Prozess oder durch Inkrementieren eines internen Referenzzählers in der DLL, falls diese bereits geladen ist. Die FreeLibrary-API dekrementiert den Leistungsindikator, bis Null erreicht ist, und entlädt dann die DLL (zu diesem Zeitpunkt werden die statischen Destruktoren für diese DLL ausgeführt).

Dazu fügen wir jetzt unsere Diagnose-DLL, die eine Liste aller ausstehenden Referenz gezählt Objekte enthält. Alle anderen DLLs verwenden eine Import-lib-Verknüpfung zur Diagnose-DLL, und die EXE verwendet auch LoadLibrary.

Wenn main beendet wird, durchläuft die EXE die Liste der zuvor geladenen DLL-Handles und ruft FreeLibrary für alle auf. Wenn die Diagnose-DLL geladen bleibt, ist sichergestellt, dass sie am Ende noch vorhanden ist. Das ist zumindest die Theorie.

Aber in welcher Reihenfolge sollten die anderen DLLs entladen werden? Wenn A.DLL über statische Zeiger auf Objekte verfügt, die in B.DLL definiert sind, sollten Sie zuerst A zuerst entladen. Sie müssen also eine Vorstellung davon haben, wie Ihre verschiedenen DLLs eine "Layered" -Architektur bilden, wobei höhere Layer von niedrigeren Layern abhängig sind, so dass Sie eine sichere Reihenfolge zum Entladen erhalten.

Sobald Sie alle DLLs entladen haben, zeigen alle Einträge in der Diagnoseliste, die auf Objekte in den DLLs verweisen, jetzt auf gültige Daten im Heap, aber die Vtable verweist auf den definierten Code durch die DLLs, die jetzt entladen wurden, so dass Sie keine virtuellen Funktionen für diese Objekte aufrufen können. Sie sollten jedoch in der Lage sein, ihre Daten zu untersuchen.

+0

Das Problem mit dem Dumping der Liste am Ende von Winmain ist, dass statische oder globale Smart Pointer immer noch refrences haben, was absolut sicher ist, da sie das Objekt freigeben, wenn sie zerstört werden. Also muss ich wirklich den Zustand dieser Liste sehen, nachdem solche Smartpointer zerstört wurden. –

+0

Gut, außer dass 99% der statischen und globalen Variablen im .exe-Modul sind, das nach der Liste scheinbar noch entladen ist. –

+0

Ich denke, ich könnte die Anwendungen als dlls erstellen, und eine Host-Exe, die die Liste enthält, lädt die App, ruft WinMain in dieser App und dann entlädt und die Liste abgibt, wenn WinMain zurückkehrt? –