Laden...

C++ DLL gibt nach Nutzung nicht alle Ressourcen frei und verursacht SEHException

Erstellt von Toxo vor 9 Jahren Letzter Beitrag vor 9 Jahren 2.652 Views
T
Toxo Themenstarter:in
64 Beiträge seit 2011
vor 9 Jahren
C++ DLL gibt nach Nutzung nicht alle Ressourcen frei und verursacht SEHException

Hallo,

ich habe momentan mit einem ungewöhnlichem Problem zu kämpfen, welches mir so noch nicht untergekommen ist und ich hoffe, dass ihr mir Hinweise geben könnt wie man in so einem Fall vorgeht.
Folgende Ausgangssituation:
Ich habe einen C++ Algorithmus welcher Bilder einliest diese verarbeitet, Ergebnisse in Bild und Textform speichert und anschließend die geladenen Ressourcen wieder freigibt. In einer C++ Konsolenanwendung funktioniert das alles wunderbar und ich kann Komplette Bildersets verarbeiten ohne Fehler.
Da ich mit C# eine GUI dazu entwerfen wollte, habe ich das ganez als unmanaged DLL Exportiert.


extern "C" { __declspec(dllexport)
void Bilder_verarbeiten(char* open_Path, char* save_Path);

Importiert unter C# habe ich es wie folgt:


 [DllImport("Bilder.dll", EntryPoint = "Bilder_verarbeiten", ExactSpelling = false, SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
        static extern void Bilder_verarbeiten(string open_Path, string save_Path);

//Aufruf
Bilder_verarbeiten(file, savetext);

Wenn ich nun in C# ein komplettes Bilderset bearbeiten will steigt der Arbeitsspeicherverbrauch immer weiter an und es sieht so aus, als ob von der DLL genutzte Ressourcen nicht wieder richtig freigegeben werden. Nachdem die Anwendung etwa 1,5GB RAM belegt erhalte ich eine SEHException. Leider weiß ich nicht wie ich an dieser Stelle debuggen kann, da der Aufruf der DLL Funktion die Exception wirft. Die Funktion tut bis zu diesem Punkt genau das was sie auch tun sollte. Ich kann die gespeicherten Ergebnisse bis zum Absturzpunkt ansehen.
In meiner Debugbaren C++ Konsolenumgebung tritt dieses Problem nicht auf.

Gibt es Möglichkeiten alle genutzten Ressourcen einer Importierten DLL manuel wieder freizugeben? Für passende Stichworte oder Artikel wäre ich dankebar, da ich so ein Problem noch nie hatte.

Grüße
Toxo

16.842 Beiträge seit 2008
vor 9 Jahren

Bei PInvoke bist Du selbst für das Freigeben von Speicher verantwortlich.
Je nachdem, wie die Ressource geladen wurde gibt es dafür verschiedene Befehle.

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Toxo,

... und anschließend die geladenen Ressourcen wieder freigibt. In einer C++ Konsolenanwendung funktioniert das alles wunderbar ...

bist du dir sicher, dass du alle Ressourcen freigibst. Was passiert, wenn du die Funktion Bilder_verarbeiten in der Konsolen-Anwendung mehrfach (testweise sogar in einer Endlosschleife) aufrufst? Bekommst du dann auch einen Fehler?

Eine SEHException ist laut Doku nur ein Wrapper für Ausnahmen aus verwaltetem Code, die nicht einer spezifischen .NET-Exceptions zugeordnet werden können. Du müsstest also erstmal herausfinden, was die eigentliche Ursache der SEHException ist. Die Doku sagt dazu:

Suchen Sie für weitere Informationen nach "nicht verwaltete Ausnahmen" und "Strukturierte Ausnahmebehandlung" in der MSDN Library.

Bzw. vermutlich besser auf englisch:

For more information, search on "unmanaged exceptions" and "Structured Exception Handling" in the MSDN Library.

herbivore

W
872 Beiträge seit 2005
vor 9 Jahren

An Deiner Stelle würde ich mir überlegen, ob Du nicht lieber C++/CLI benutzt...das ist in Deinem Fall wahrscheinlich einfacher

T
Toxo Themenstarter:in
64 Beiträge seit 2011
vor 9 Jahren

bist du dir sicher, dass du alle Ressourcen freigibst. Was passiert, wenn du die Funktion Bilder_verarbeiten in der Konsolen-Anwendung mehrfach (testweise sogar in einer Endlosschleife) aufrufst? Bekommst du dann auch einen Fehler?

Ja ich habe das gleich Bildset von etwa 250 Bildern in der Konsolenanwendung durchlaufen lassen und das komplette Set wird ohne Fehlermeldung verarbeitet.
Da je nach Bild in dieser Umgebung 1-3 Minuten für einen Durchlauf benötigt werden, konnte ich in diesem Durchlauf den Arbeitsspeicherverbrauch im Taskmanager beobachtet und man sieht an den Spitzen sehr gut, dass nach dem bearbeiten eines Bildes die Ressourcen wieder freigegeben werden. Einen stetigen Anstieg nach jedem Bild wie in der C# Umgebung und ein Abbruch nach etwa 100 Bildern tritt dort nicht af.
Ich habe jetzt folgendes probiert. Nach jedem Funktionsaufruf hatte ich die Hoffnunng die genutzten Ressourcen wie folgt wieder frei zu geben:


 foreach(ProcessModule mod in Process.GetCurrentProcess().Modules)
                                {
                                if ("Bilder.dll" == mod.ModuleName)
                                    mod.Dispose();
                                  }

Nachdem das nicht zum Erfolg führte habe nach dem Empfangen der Exception die DLL entladen um zu schhauen ob der Fehler wirklich an dieser Stelle liegt:


[DllImport("kernel32", SetLastError = true)]
        static extern bool FreeLibrary(IntPtr hModule);
 foreach(ProcessModule mod in Process.GetCurrentProcess().Modules)
                                {
                                if ("Bilder.dll" == mod.ModuleName)
                                    FreeLibrary(mod.BaseAddress);

                                  }

Meine Vermutung war, dass nach diesem Vorgang beanspruchte Ressourcen wieder frei sein müssten. Leider ist dies nicht der Fall und jetzt weiß ich nicht wie ich an die Ursache für dieses Problem komme. Mit dem Tool VMMap sehe ich, dass mein Programm beim Auslösen der Exception 1,5GB private Heap Data im RAM beansprucht und das hilft mir bei der Fehlersuche leider auch noch nicht weiter.

Für weitere Hinweise bin ich dankbar.

An Deiner Stelle würde ich mir überlegen, ob Du nicht lieber C++/CLI benutzt...das ist in Deinem Fall wahrscheinlich einfacher

Das ist eine Option die ich noch nicht verfolgen möchte, da ich im C++ Code mehrere externe Libraries zur Bildverarbeitung nutze, welche CLI nativ nicht unterstützen. Falls ich das Problem nicht anders gelöst bekomme denke ich über einen C++/CLI Wrapper nach.

W
872 Beiträge seit 2005
vor 9 Jahren

Wieso benutzt Du Cdecl - schon mal StdCall probiert? Wie baust Du denn?

T
Toxo Themenstarter:in
64 Beiträge seit 2011
vor 9 Jahren

Ich habe das Problem jetzt gelöst, indem ich das ganze Projekt als 64Bit DLL realisiert habe. Mit dieser DLL wird das komplette Set in der GUI abgearbeitet ohne Absturz oder sonstige unerwünschte Effekte. Warum dies bei einer 32 Bit DLL und Anwendung nicht der Fall ist erschließt sich mir leider immer noch nicht aber ich bin jedem dankbar, der sich zu meinem Problem Gedanken gemacht hat um mir zu helfen.

Grüße Toxo