Ich habe eine EXE-Datei mit einer DLL-Datei, die eine andere DLL-Datei verwendet. Diese Situation ist entstanden:
In DLL-Datei 1:
%Vor%In DLL-Datei 2:
%Vor% Im Freigabemodus funktioniert alles einwandfrei. Aber im Debug-Modus habe ich einen Assertionsfehler im Destruktor eines std::strings
im Ordnervektor (wenn Ordner am Ende von aFunction den Gültigkeitsbereich verlassen):
dbgheap.c : line 1274
Ich nehme an, das liegt daran, dass der Speicher auf dem Heap der DLL-Datei 1 zugewiesen wurde, aber in DLL-Datei 2 freigegeben wird.
Der Kommentar in dbgheap.c
scheint ziemlich hartnäckig zu sein, dass dies ein Problem ist.
Warum ist das ein Problem, wenn es gut zu funktionieren scheint, wenn ich es einfach ignoriere? Gibt es eine nicht durchsetzungsschwache Möglichkeit, dies zu tun?
Wie Sean bereits gesagt hat, ignoriert der Release-Build einfach diese Anweisung delete, also ist das Beste, worauf Sie hoffen können, ein Speicherleck.
Wenn Sie Kontrolle darüber haben, wie beide DLL-Dateien kompiliert werden, müssen Sie die Einstellungen Multi-threaded-DLL (/ MDd) oder Multi-threaded DLL (/ MD) für die Laufzeitbibliothek verwenden. Auf diese Weise verwenden beide DLL-Dateien dasselbe Laufzeitsystem und teilen denselben Heap.
Der Nachteil ist, dass Sie das Laufzeitsystem zusammen mit Ihrer Anwendung installieren müssen (Microsoft bietet dafür ein Installationsprogramm an). Es funktioniert gut auf Ihrem Entwicklungscomputer, da Visual Studio dieses Laufzeitsystem ebenfalls installiert, aber auf einem neu installierten Computer meldet es fehlende DLL-Dateien.
Wie andere sagen, kann das Problem gelöst werden, indem sichergestellt wird, dass der CRT zwischen den zwei Modulen geteilt wird. Es gibt jedoch häufig Szenarien, in denen dieser Vertrag schwer durchsetzbar ist.
Der Grund dafür ist, dass die Verknüpfung mit einem freigegebenen CRT nicht funktioniert, wenn EXE und DLL nicht mit derselben CRT Version verknüpft sind (wie in 6.0, 7.0, 8.0). Wenn Sie beispielsweise eine DLL verwenden, die in VC6.0 erstellt wurde, und versuchen, sie mit einem EXE-Build in VS2010 zu verwenden, erhalten Sie das gleiche Problem wie zuvor. Die beiden CRT-Versionen werden in Ihren Prozess geladen und verwenden jeweils ihren eigenen Heapspeicher für die Zuweisung. Unabhängig davon, ob EXE und DLL "gemeinsam genutzte" CRTs verwenden, sind sie nicht identisch.
Eine bessere Vorgehensweise für eine API wäre, sicherzustellen, dass Objekte, die auf einer Seite zugeordnet sind, ebenfalls auf der gleichen Seite zerstört werden. Ich weiß, das klingt hässlich, aber es ist der einzige Weg, um sicherzustellen, dass eine DLL binär kompatibel bleibt.
Wahrscheinlich hat der Release-Build das gleiche Problem, aber Release-Builds werden nicht bestätigt. Sie ignorieren das Problem einfach. Möglicherweise sehen Sie nie ein Problem. Oder Sie sehen möglicherweise Datenkorruption. Oder du siehst einen Absturz. Vielleicht werden nur Ihre Benutzer Fehler entdecken, die Sie einfach nicht reproduzieren können.
Ignorieren Sie CRT-Assertionen nicht.
Sie sollten immer den entsprechenden Deallocator verwenden (den, der mit dem verwendeten Zuordner übereinstimmt). Wenn Sie statische CRT-Bibliotheken in Ihren DLL-Dateien verwenden, verwenden die DLL-Dateien unterschiedliche Heaps. Sie können den Speicher nicht über Heaps hinweg freigeben. Ordnen Sie einen Speicherblock zu und heben Sie die Zuweisung auf, indem Sie denselben Heapspeicher verwenden.
Wenn Sie in Ihren DLL-Dateien gemeinsam genutzte CRT-Bibliotheken verwenden, sollten sie denselben Heap verwenden und Sie können sie in einer DLL-Datei zuordnen und in einem anderen freigeben.
Dies ist nur ein Problem, wenn die Anwendung oder eine (oder mehrere) der DLL-Dateien mit der statischen Version der Standardbibliothek verknüpft ist. Dies wurde vor etwa einem Jahrzehnt von MS gelöst, die die Shared-Library-Version der Standardbibliothek veröffentlicht haben. Dies liegt daran, dass jede Version der Standardbibliothek einen eigenen internen Heap erstellt und Sie daher den Speicher mit mehreren Heaps auf den richtigen Heapspeicher freigeben müssen. Bei Verwendung der freigegebenen Version der Standardbibliothek verwenden alle denselben Heap.
Es ist heutzutage gängige Praxis für die Anwendung und alle DLL-Dateien sollten so gebaut werden, dass sie die dynamische Version der Standardbibliothek verwenden.
Wenn Sie einen eigenen Heap erstellen und Speicher von diesem Heap zuweisen, besteht der einzige Nachteil des oben genannten Problems. Dies ist jedoch ein sehr spezielles Verfahren, das nur in seltenen Situationen durchgeführt wird (und wenn Sie genug verstehen, es zu benutzen, dann werden Sie nicht in der Lage sein, diese Frage zu stellen).
Tags und Links c++ dll debugging memory-management assert