DLL laden/entladen



  • Hallo zusammen

    Habe eine eigene DLL (CG2009) welche in einem eigenen Programm (BCB6) verwendet wird.
    Ich schaue mir momentan den Speicherverbrauch (Private Bytes) des Programmes mit dem ProcessExplorer an.

    Vor dem Laden der DLL bin ich bei 6,1 MB nach dem Laden 8,1 MB und nach dem Entladen 7,4 MB.
    Da die DLL mehrfach geladen und entladen wird, geht mir irgendwann der Speicher aus.
    Im Ereignissprotokoll werden die entsprechenden Module geladen, sowie auch wieder entladen.

    Modul geladen: AteHash.dll. Ohne Debug-Infos. Basisadresse: 0x02470000. Prozeß Analyse_Testprotocols.exe (0x1060)
    Modul geladen: MSIMG32.dll. Ohne Debug-Infos. Basisadresse: 0x76380000. Prozeß Analyse_Testprotocols.exe (0x1060)
    Thread-Ende: Thread-ID: 0x00000E04. Prozeß Analyse_Testprotocols.exe (0x1060)
    Modul entladen: AteHash.dll. Prozeß Analyse_Testprotocols.exe (0x1060)
    Modul entladen: MSIMG32.dll. Prozeß Analyse_Testprotocols.exe (0x1060)
    

    Hier noch ein Codeauszug:

    int DllCheckMd5HashFile(AnsiString sFileName)
    {
        HANDLE hDll;
        CheckMd5FromFileUni_t *CheckMd5FromFileUni;
        int iReturn;
        char *cFileName;
    
        //convert filename to char*
        cFileName = new char[sFileName.Length() + 1];
        strcpy(cFileName, sFileName.c_str());
    
        //load functions from dll
        hDll = LoadLibrary("AteHash.dll");
    
        //check handle
        if(hDll == NULL)
        {
            Application->MessageBox(Log(GetSystemErrorMessage(), "LoadLibrary(\"AteHash.dll\"):").c_str(), (ERROR_AT).c_str(), MB_ICONERROR + MB_OK);
            return 0;
        }
        else
        {
            CheckMd5FromFileUni = (CheckMd5FromFileUni_t *)GetProcAddress(hDll, "_CheckMd5FromFileUni");
        }
    
        //this function checks the unicode style hash and AnsiString style hash
        iReturn = CheckMd5FromFileUni(cFileName);
        if(FreeLibrary(hDll) == 0)
        {
            Log(POSITION_AT, GetSystemErrorMessage());
        }
    
        return iReturn;
    }
    

    Kann sich dies jemand erklären?

    Außerdem wollte ich mir den "Referenz Zähler" der DLL in der Registry (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs) anschauen, jedoch meine DLL taucht hier gar nicht auf.

    MfG Stephan



  • Bis auf die Tatsache, dass du den Speicher von cFileName nicht freigibst sehe ich erstmal nichts.



  • Hallo

    Ich sehe überhaupt keinen Grund, warum du mit cFileName einen extra C-String benutzt.

    Auch der Speicherverbrauch ist noch nicht ausssagekräftig, denn Windows behält sehr wohl aus Geschwindigkeitsgründen DLLs (oder Teile davon) im Speicher. Du solltest mal die Funktion mehrmals hintereinander ausführen, und schauen ob jedesmal der Gesamtverbrauch weiter steigt.

    Schlußendlich hat das wenig mit dem Builder zu tun, sondern ist Windows-Sache.

    bis bald
    akari



  • Dieser Thread wurde von Moderator/in akari aus dem Forum VCL (C++ Builder) in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • 1. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs hat nur was mit dem Installer zu tun.
    2. Das wird wohl in Deiner DLL liegen. Wenn die DLL beim Laden Speicher allokiert und diese beim Beenden nicht freigibt, so wird das eben darin liegen.



  • Hallo zusammen

    Das der Speicher von cFileName nicht freigegeben wird, ist mir auch schon aufgefallen, ist bereits korrigiert, jedoch dies sollte nicht das Problem sein.

    akari schrieb:

    Auch der Speicherverbrauch ist noch nicht ausssagekräftig, denn Windows behält sehr wohl aus Geschwindigkeitsgründen DLLs (oder Teile davon) im Speicher. Du solltest mal die Funktion mehrmals hintereinander ausführen, und schauen ob jedesmal der Gesamtverbrauch weiter steigt.

    Der Speicher steigt beim jedem Aufruf, bis irgendwann der Hauptspeicher voll ist.

    Martin Richter schrieb:

    1. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs hat nur was mit dem Installer zu tun.

    Das mit der Registry habe ich nicht verstanden.
    Ich war seither der Meinung, daß die Anzahl wie oft eine DLL angefordert wurde immer in der Registry gespeichert wird. Dies wiederspricht deiner Aussage, und was meinst Du mit Installer?

    Martin Richter schrieb:

    2. Das wird wohl in Deiner DLL liegen. Wenn die DLL beim Laden Speicher allokiert und diese beim Beenden nicht freigibt, so wird das eben darin liegen.

    Das der Speicher _nicht_ in der DLL allokiert wird bin ich mir eigentlich zu 99% sicher, denn beim Laden der DLL passiert in der DLL noch gar nichts, und zu diesem Zeitpunkt steigt bereits der Speicherverbrauch an. Sobald die Funktion in der DLL ausgeführt wird ändert sich jedoch am Speicherverbrauch nichts.

    Noch irgendwelche Ideen?
    MfG Stephan



  • Stephan schrieb:

    Martin Richter schrieb:

    1. HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\SharedDLLs hat nur was mit dem Installer zu tun.

    Das mit der Registry habe ich nicht verstanden.
    Ich war seither der Meinung, daß die Anzahl wie oft eine DLL angefordert wurde immer in der Registry gespeichert wird. Dies wiederspricht deiner Aussage, und was meinst Du mit Installer?

    Wenn mehrere Programm ein und die selbe DLL installieren, dann wird dies in diesem Ast mitgezählt wieviele Program diese DLL gemeinsam nutzen.
    Wird das ein Programm deinstalliert und der Zähler dieses Eintrages fällt auf 0 wird die DLL entfernt vom Rechner.

    Lies die MSDN bzgl. Installer und shared DLLs...

    Stephan schrieb:

    Martin Richter schrieb:

    2. Das wird wohl in Deiner DLL liegen. Wenn die DLL beim Laden Speicher allokiert und diese beim Beenden nicht freigibt, so wird das eben darin liegen.

    Das der Speicher _nicht_ in der DLL allokiert wird bin ich mir eigentlich zu 99% sicher, denn beim Laden der DLL passiert in der DLL noch gar nichts, und zu diesem Zeitpunkt steigt bereits der Speicherverbrauch an. Sobald die Funktion in der DLL ausgeführt wird ändert sich jedoch am Speicherverbrauch nichts.

    Irrtum! Evtl. solltest Du Dir erstmal die Basics über Dlls in der MSDN aneignen.

    Sobald die DLL geladen wird, werden auch andere mit dieser DLL verbundene DLs geladen. Jewels in jeder DLL wird DllMain ausgeführt. In diesem DllMain Code kann sehrwohl sofort Speicher allokiert werden.
    Gleiches beim entladen.

    Eine DLL kann sehr wohl nur durch das Laden Leaks verursachen wenn Sie schlecht programmiert wurde.



  • Hallo zusammen

    Martin Richter schrieb:

    Irrtum! Evtl. solltest Du Dir erstmal die Basics über Dlls in der MSDN aneignen.

    Sobald die DLL geladen wird, werden auch andere mit dieser DLL verbundene DLs geladen. Jewels in jeder DLL wird DllMain ausgeführt. In diesem DllMain Code kann sehrwohl sofort Speicher allokiert werden.
    Gleiches beim entladen.

    Eine DLL kann sehr wohl nur durch das Laden Leaks verursachen wenn Sie schlecht programmiert wurde.

    Das es möglich ist bereits beim Laden bzw Entladen Code auzuführen ist mir klar, allerdings macht dies meine DLL nicht, bzw ich habe keinen Code dafür geschrieben.
    Was ich im Ereignissprotokoll gesehen habe ist daß, eine weitere DLL (MSIMG32.dll) geladen wird. Nach kurzem googeln weiß ich nun das diese DLL von MS ist und etwas mit GDI zu tun hat.
    Ich gehe davon aus, daß diese DLL (MSIMG32.dll) soweit OK ist.

    MfG Stephan



  • Wenn Du die DLL selbst geschrieben hast.
    Frage 1: Wie sieht Dein DllMain Code aus
    Frage 2: Verwendset Du statische Objekte/Klassen, die beim Laden der DLL initialisiert werden? Wenn ja welche?
    Frage 3: Verwendest Du andere LIBs deren Code Du nutzt und deren FunktionsweiseDu evtl. nicht kennst.



  • Hallo zusammen

    Martin Richter schrieb:

    Frage 1: Wie sieht Dein DllMain Code aus

    Da ich CodGear 2009 (ehemals Borland) verwende, müßte dies mein Dllmain sein.

    int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
    {
        return 1;
    }
    

    Martin Richter schrieb:

    Frage 2: Verwendset Du statische Objekte/Klassen, die beim Laden der DLL initialisiert werden? Wenn ja welche?

    Es wird nur eine Klasse verwendet, welche ein statisches Objekt verwendet. Habe jedoch mit einer MessageBox überprüft, das der Destruktor aufgerufen wird. Die restlichen C-Dateien sind alles nur einzelne Funktionen, welche nach momentanem Wissensstand keine globalen Variablen verwenden.

    Martin Richter schrieb:

    Frage 3: Verwendest Du andere LIBs deren Code Du nutzt und deren FunktionsweiseDu evtl. nicht kennst.

    Ich verwende einen Satz externen Funktionen um einen MD5 Hash zu errechnen.
    Diese muß ich mir nochmals genau anschauen.

    MfG Stephan



  • Welche anderen DLLs werden durch diese DLL geladen und wieder entladen?



  • behebe erstmal das speicherleck. vielleicht bringts ja was.



  • Hallo zusammen

    Martin Richter schrieb:

    Welche anderen DLLs werden durch diese DLL geladen und wieder entladen?

    Es werden explizit keine anderen DLLs per Code von mir geladen. Was ich im Ereignissprotokoll sehe, ist das eine DLL MSIMG32.dll geladen wird, welche laut Google von MS kommt und etwas mit GDI zu tun hat.

    leck! schrieb:

    behebe erstmal das speicherleck. vielleicht bringts ja was.

    Von welchem Speicherleck redest Du?
    Wenn Du die Sache mit cFileName meinst, die ist schon lange erledigt.

    Meine neusten Erkenntnise sehen jedoch nun so aus, daß wenn ich im Linker die Verwendung der dynamischen RTL einstelle, das Problem behoben ist.
    Allerdings möchte ich die RTL nicht dynamisch verwenden, sondern statisch.

    Meiner Meinung nach ist dies dann ja nun doch ein Builder Problem, oder nicht?
    Wenn ihr dies genauso seht, bitte wieder zurück verschieben. Danke.

    Habe als weiteren Test eine neue DLL mit einer leeren Funktion erstellt und diese exportiert.
    Anschließend eine neue Anwendung welche mit einem Button die DLL dynamisch lädt (LoadLibrary) und wieder entläd (FreeLibrary).
    Wenn ich den Button nun mehrfach drücke sehe ich das der Speicherverbrauch wieder ansteigt.
    Sobald ich auf dynamische RTL umstelle funktioniert es wie es soll. Habe auch schon versucht wie angegeben MEMMGR.LIB mit zu linken. Jedoch ohne Veränderung.

    Bin momentan sehr ratlos.

    MfG Stephan



  • RTL?



  • Hallo Martin

    Martin Richter schrieb:

    RTL?

    Sorry, für alle nicht Builderanwender, hier geht es um die Laufzeitbibliotheken, deshalb auch die Vermutung, daß es sich hierbei um ein builderspezifische Problem handelt.
    Die Laufzeitbibliothek kann entweder dynamisch oder statisch gelinkt werden. Wobei, meiner Meinung nach, die meisten Builderanwender die statische Variante bervorzugen.

    MfG Stephan



  • Und Du bist sicher, dass der DllMain Entry Point stimmt, so dass der Builder seinen Init/Uninit durchführen kann.

    Wennm man in einem MS Produkt, den Entry-Point der DLL selbst verbiegt unddie CRT umgeht, gibt es auch Leaks, wenn man dann doch die CRT benutzt!



  • Hallo Martin

    Das der Entry Point stimmt bin ich mir eigentlich sicher, da der Builder den Code automatisch erstellt, und ich hier nichts geändert habe.
    Mit der CRT meinst Du die Runtime Library, oder?

    Kann der Beitrag wieder zurück ins Builder Forum verschoben werden, oder ist dies Technisch nicht möglich?

    MfG Stephan



  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum WinAPI in das Forum VCL (C++ Builder) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Ja mit CRT meine ich die C Runtime Library.

    Ich habe den Beitrag verschoben! Viel Glück bei der weiteren Suche.



  • Hallo zusammen

    @Martin Richter
    Vielen dank für dein Hilfe, und ich glaube Glück kann ich gebrauchen 😉

    Also ich bin wieder da mit meinem Problem, denn so wie es aussieht, hat es etwas mit dem Builder.

    Nochmals eine kurze Zusammenfassung:
    Sobald ich eine DLL (erstellt mit CG2009 und statischer RTL) dynamisch in einem Projekt (CG2009) lade und wieder entlade (mehrfach) steigt der Speicherverbrauch immer weiter an. Nach jedem entladen bleiben ca. 1,2 MB übrig.
    Habe DLL und Anwendung schon mit MEMMGR.LIB sowie ohne erstellt, jedoch ohne Erfolg.
    Wenn die DLL mit dynamischer RTL erstellt wird, funktioniert alles wie es soll.

    Kann dies jemand erklären, bzw bei sich nachvollziehen?

    Bin langsam mehr als ratlos.

    MfG Stephan


Anmelden zum Antworten