2012-04-14 17 views
3

So habe ich eine DLL, die ich in C++ geschrieben habe. Es reserviert jedoch Speicher mit GlobalAlloc(). Um Speicherlecks zu vermeiden, möchte ich diese Zuordnungen verfolgen und alle auf die Zerstörung der DLL entziehen.C++ DLL Unload Destruktor?

Gibt es eine Möglichkeit, eine Funktion zu schreiben, die aufgerufen wird, wenn meine DLL entladen wird? Eine Sache, die ich mir vorstellen kann, ist das Erstellen eines globalen Objekts in meiner DLL und das Schreiben der Speicher freien Aufrufe in seinem Destruktor, aber das scheint wie Overkill. Meine andere Idee ist, nur auf das Betriebssystem zu verlassen, um den Speicher freizugeben, wenn die DLL entladen, aber das scheint schmutzig.

Danke

+0

Der Speicher wird zugewiesen, wenn die LPCSTR GetCSV() - Funktion aufgerufen wird. Im Grunde kopiere ich Speicher von einer lokalen Std-Zeichenfolge in den Speicher, den ich mit GlobalAlloc() reserviere, um sicherzustellen, dass mein Aufrufer Zugriff auf den Speicher hat, nachdem die Funktion zurückkehrt. Ich habe etwas Code hinzugefügt, um Speicher von alten Aufrufen von GetCSV() aufzuräumen, aber ich werde nicht den letzten Fall behandeln, wenn die DLL entladen wird, da dies anscheinend automatisch für mich erledigt wird. Dieser [Artikel] (http://blogs.msdn.com/b/oldnewthing/archive/2012/01/05/10253268.aspx) (durch Beantworter verbunden), ist wirklich nett. – Amil

Antwort

6

Gibt es eine Möglichkeit, eine Funktion zu schreiben, die aufgerufen wird, wenn meine DLL entladen wird? Eines, was ich denken kann, ist ein globales Objekt in meinem DLL Erstellen und Schreiben den Speicher kostenlose Anrufe in seinem destructor

das möglich ist, obwohl ich genau glauben, wenn Ihr Objekt destructor wird undefined aufgerufen wird.

Das könnte Sie interessieren: DLL_PROCESS_DETACH, und obwohl Sie vermeiden sollten, etwas Wichtiges in DllMain zu tun, scheint es, dass die Freigabe von Ressourcen hier akzeptabel ist. Beachten Sie die Einschränkungen:

Wenn eine DLL aus einem Prozess als Ergebnis einer nicht erfolgreichen Last des DLL, Beendigung des Prozesses oder einen Aufruf von Freelibrary entladen ist, wird das System nicht den Einstiegspunkt der DLL aufrufen Funktion mit dem Wert DLL_THREAD_DETACH für die einzelnen Threads des Prozesses. Die DLL sendet nur eine DLL_PROCESS_DETACH-Benachrichtigung. DLLs können diese Gelegenheit nutzen, um alle Ressourcen für alle Threads zu bereinigen, die der DLL bekannt sind.

Bei der Behandlung von DLL_PROCESS_DETACH sollte eine DLL Ressourcen wie Heapspeicher nur freigeben, wenn die DLL dynamisch entladen wird (der Parameter lpReserved ist NULL). Wenn der Prozess beendet wird (der Parameter lpvReserved ist nicht NULL), sind alle Threads im Prozess mit Ausnahme des aktuellen Threads entweder bereits beendet oder wurden explizit durch einen Aufruf der ExitProcess-Funktion beendet, wodurch möglicherweise Prozessressourcen wie Heaps verbleiben in einem inkonsistenten Zustand. In diesem Fall ist es für die DLL nicht sicher, die Ressourcen zu bereinigen. Stattdessen sollte die DLL dem Betriebssystem ermöglichen, den Speicher zurückzufordern.

Sie müssen möglicherweise auf auszuarbeiten, warum Ihre DLL auf den Speicher halten kann, wenn man von der DLL erstellt zahlreiche Objekte haben, sollten sie einen definierten Lebenszyklus haben und reinigen sich am Ende ihres Lebens auf.

Wenn sie keine Objekte sind (d. H.Speicher wird zugewiesen und über Funktionen an den Aufrufer zurückgegeben) Warum nicht die Verantwortung wieder auf denjenigen setzen, der Ihre DLL verbraucht? Sie können die Erinnerung befreien. Die Terminaldienste-Bibliothek folgt diesem Muster (WTSFreeMemory).

Wenn die Ressourcen langlebig sind und für die Lebensdauer Ihrer Bibliothek vorhanden sein müssen, lassen Sie den Verbraucher den Lebenszyklus Ihrer Bibliothek steuern. Schreibe zwei Funktionen: MyFrameworkStartup und MyFrameworkShutdown wie geeignet. Winsock folgt diesem Muster (WSAStartup und WSACleanup).

Meine andere Idee ist, nur auf das Betriebssystem zu verlassen, um den Speicher freizugeben, wenn die DLL entladen, aber das scheint schmutzig.

You'll be okay if the process is exiting:

Kümmere dich nicht um Speicher zu befreien; Es wird alles verschwinden, wenn der Prozessadressraum zerstört wird. Mach dir keine Sorgen um die Griffe zu schließen; Handles werden automatisch geschlossen, wenn die Prozess-Handle-Tabelle zerstört wird. Versuchen Sie nicht, andere DLLs aufzurufen, da diese anderen DLLs möglicherweise bereits ihre DLL_PROCESS_DETACH-Benachrichtigungen erhalten haben. In diesem Fall verhalten sie sich möglicherweise auf dieselbe Weise wie ein Delphi-Objekt fehlerhaft, wenn Sie versuchen, es nach der Ausführung seines Destruktors zu verwenden .

Stellen Sie sicher, dass Sie den gesamten Artikel und die Kommentare lesen und verstehen, bevor Sie die Strategie "Nichts tun" implementieren.

+0

Danke! Dies ist perfekt. Vor allem der Hinweis, dass man sich keine Gedanken über die Speicherfreigabe machen muss. – Amil

2

Wie/wann ist der Speicher zugewiesen? In der Regel besteht die sinnvollste Option darin, eine Symmetrie beizubehalten (Konstruktorzuweisungen, Destruktor-Deallocates oder Speicher, der beim Laden der DLL und beim Entladen der DLL freigegeben wird).

In jedem Fall, wenn Sie benachrichtigt werden möchten, wenn die DLL entladen ist, schauen Sie in die DllMain Funktion und speziell den DLL_PROCESS_DETACH Parameter.

+1

Entsprechend der von Ihnen angegebenen Verknüpfung ruft der von der Laufzeitbibliothek bereitgestellte Standard-DllMain die Konstruktoren/Destruktoren globaler Objekte auf. Daher denke ich, nur ein globales Objekt in der DLL mit entsprechenden Konstruktor/Destruktor sollte ausreichen. – celtschk

+0

Danke für die Antwort! Der Speicher wird zugewiesen, wenn die Funktion 'LPCSTR GetCSV()' aufgerufen wird. Im Grunde kopiere ich Speicher von einem lokalen Std-String in den Speicher, den ich mit 'GlobalAlloc()' reserviere, nur um sicherzustellen, dass mein Aufrufer Zugriff auf den Speicher hat, nachdem die Funktion zurückkehrt. Ich habe etwas Code hinzugefügt, um Speicher von alten Aufrufen von 'GetCSV()' aufzuräumen, aber ich werde nicht den letzten Fall behandeln, wenn die DLL entladen wird, da dies anscheinend automatisch für mich erledigt wird. – Amil

1

Die DllMain function wird aufgerufen, mit FdwReason auf DLL_PROCESS_DETACH festgelegt, wenn eine DLL entladen wird. Stellen Sie, wie in der Dokumentation beschrieben, sicher, dass Sie den Wert von lpvReserved überprüfen und nur freien Speicher, wenn es NULL ist; Sie should not free memory if the process is terminating.

+0

Danke für die nette und einfache Antwort! – Amil