Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Speicherproblem mit Objekten in DLL (https://www.delphipraxis.net/214210-speicherproblem-mit-objekten-dll.html)

BastiFantasti 4. Dez 2023 19:19

Speicherproblem mit Objekten in DLL
 
Hallo zusammen,

ich habe ein Problem mit dem Freigeben von Objekten in einer DLL.

Ich Rufe eine Funktion zum Erzeugen eines Objekts aus einem nach JSON serialisierten String auf.

Dann wird das Objekt verwendet und schlussendlich mit FreeAndNil wieder frei gegeben.
Alle generischen Listen, die Teil der Klasse sind, werden im Destruktor ordnungsgemäß freigegeben (also erst die Objekte in den TList<TIrgendeinObjekt> Elementen und abschließend die Listen selber.

Wenn ich den Constructor und den Destructor in einer Testanwendung (normale Win32 exe) zyklisch aufrufe und genau das selbe Objekt aus den serialisierten Daten erzeuge, wird der Speicher von der Anwendung einmalig allokiert, von Windows reserviert und entsprechend immer wieder verwendet.
Das heißt, der Speicherbedarf der Anwendung steigt dauerhaft um ca 2-3MB. Es handelt sich um ein größeres Objekt mit längerem Tracelog, daher die Größe.

Wenn ich nun die gleiche Klasse in eine Win32 dll verfrachte und das Objekt dort instanziere und wieder freigebe, steigt der Speicherverbrauch bei jedem Aufruf aufs neue an. D.h. mit jedem neuen Durchlauf des Konstruktors schnappt sich die Anwendung zusätzliche 2-5MB.

Wie kann ich dieses Verhalten erklären - und noch viel wichtigter - wie kann ich es abstellen :roll:


Viele Grüße
Bastian

himitsu 4. Dez 2023 20:09

AW: Speicherproblem mit Objekten in DLL
 
Wird Shared Memory verwendet?

Erstellen, Verwenden und Freigeben im selben Modul (EXE/DLL) oder wird da etwas zwischen EXE und DLL übergeben?

BastiFantasti 5. Dez 2023 04:16

AW: Speicherproblem mit Objekten in DLL
 
Ja SharedMem habe ich als erste Unit in den Uses der DPR mit drin (habe es auch ohne versucht)

Der Aufruf des Objekts ist wie folgt:

- dpr Datei beinhaltet die eigentlich Unit (mit Form)
- die "Unit mit Form" wird in einem TThread.execute gestartet bzw. mit CreateForm erzeugt
- die TThread.execute Ereignis wird laut Breakpoint nur einmalig durchlaufen
- in der "Unit mit Form" wird das Objekt in einer Funktion (Abarbeitung der Anfrage von ausserhalb der DLL instanziert, verwendet und wieder freigegeben)
- Das eigentliche Objekt steckt in seiner eigenen Unit, die die ganze Klasse enthält


- von der aufrufenden Anwendug wird ein Record an die DLL übergeben.
Der Record ist eine definierte Schnittstelle der aufrufenden Anwendug.
Es handelt sich um eine Integration in einen FTP Server, der die relevanten Daten an die DLL übergibt (FTP Benutzernamen, übertragene Datei, Operation, ...)
Immer wenn eine Datei übertragen wird, wird der Inhalt dem FTP Benutzer zugeordnet und der Inhalt der Datei mit der eigentlichen Anforderung ausgewertet.

Ich hoffe ich habe das verständlich aufgelistet :wink:

jaenicke 5. Dez 2023 07:44

AW: Speicherproblem mit Objekten in DLL
 
Die entscheidende Frage ist doch:
Wird der Destruktor in der DLL durchlaufen, sprich kommst du an einem Haltepunkt darin an?

Wenn Hostanwendung und DLL in der gleichen Projektgruppe liegen, solltest du direkt in der DLL debuggen können, sofern Debuginformationen und ggf. externe Debugsymbole aktiviert sind. Ansonsten kannst du die Hostanwendung auch als solche im DLL-Projekt eintragen und dieses dann starten.

Wichtig ist dabei, dass Speicher nicht unbedingt sofort wieder freigegeben wird. Zur Optimierung behält der Speichermanager den Speicher ggf. auch, um ihn später erneut zu verwenden. Deshalb kann man am Speicherverbrauch nicht unmittelbar sehen, ob der Speicher freigegeben wird.

In den Beispielen zu FastMM4 z.B. ist ein Beispiel enthalten, wie man die Speicherbelegung direkt sehen kann. Außerdem zeigt es Speicherlecks beim Beenden an. Das funktioniert in einfacher Form auch mit ReportMemoryLeaksOnShutdown, das in Delphi bereits integriert ist.

Bezüglich des Records:
Ich persönlich würde die Klasse in der DLL (oder eine zusätzliche Verwaltungsklasse) einfach mit Implementierung eines Interfaces implementieren, das dann von der Hostanwendung abgerufen werden kann. Dann kann man die Klasse dort direkt nutzen.
Dafür kannst du z.B. mein AppCentral Projekt nutzen:
https://www.delphipraxis.net/213199-...ng-dlls-c.html

BastiFantasti 6. Dez 2023 08:16

AW: Speicherproblem mit Objekten in DLL
 
Die DLL wird zu dem Zeitpunkt nicht beendet.
D.h. der Destruktor wird auch noch nicht durchlaufen.
Die DLL läuft in der Anwendung über mehrere Tage/Wochen.

FastMM4 habe ich in die DLL eingehängt und bekomme beim Beendern aber nur ein Speicherleck von ein paar kB.
Das Problem ist aber, dass obwohl das Objekt zur Laufzeit instanziert und Freigegeben wird, die DLL den Speicher immer aufaddiert und nichts mehr davon freigibt.
D.h. nach ein paar Iterationen belegt die DLL ihre vollen 2GB Speicher.

Wie gesagt funktionieren die gleichen Aufrufe zum Erstellen und Freigeben des Objekts in einer Testanbwendung wie erwartet.

TiGü 6. Dez 2023 09:28

AW: Speicherproblem mit Objekten in DLL
 
Fang mal von vorne an und mache dir ein ganz kleines Konsolenprogramm (kein VCL!) und rufe von dort die exportierte DLL-Funktion auf.

BastiFantasti 6. Dez 2023 09:41

AW: Speicherproblem mit Objekten in DLL
 
Ja ich glaube da werde ich nicht drum rum kommen...
Ich werde berichten

Sinspin 6. Dez 2023 12:08

AW: Speicherproblem mit Objekten in DLL
 
Du übergibst der Dll Funktion den String? Um Spass mit langen Strings zu vermeiden verwende ich für die Kommunikation mit Dll's Named Pipes oder gleich einen Netzwerk Socket.

jaenicke 6. Dez 2023 12:12

AW: Speicherproblem mit Objekten in DLL
 
Zitat:

Zitat von BastiFantasti (Beitrag 1530460)
Die DLL wird zu dem Zeitpunkt nicht beendet.
D.h. der Destruktor wird auch noch nicht durchlaufen.

Wenn kein Destruktor durchlaufen wird, wird auch nichts freigegeben. Du hast eingangs doch aber genau das beschrieben:
Zitat:

Zitat von BastiFantasti (Beitrag 1530409)
Wenn ich nun die gleiche Klasse in eine Win32 dll verfrachte und das Objekt dort instanziere und wieder freigebe, steigt der Speicherverbrauch bei jedem Aufruf aufs neue an. D.h. mit jedem neuen Durchlauf des Konstruktors schnappt sich die Anwendung zusätzliche 2-5MB.

Darum kann ich dir nicht mehr folgen, wenn du plötzlich sagst, dass gar kein Destruktor durchlaufen wird. Wo wird denn nun Speicher reserviert und wo soll er freigegeben werden? Egal, ob da nun ein Destruktor involviert ist oder du manuell FreeMem aufrufst, kannst du doch dort einen Haltepunkt setzen, um zu prüfen, ob die Freigabe durchgeführt wird.

Zitat:

Zitat von Sinspin (Beitrag 1530476)
Du übergibst der Dll Funktion den String? Um Spass mit langen Strings zu vermeiden verwende ich für die Kommunikation mit Dll's Named Pipes oder gleich einen Netzwerk Socket.

Wozu der Aufwand? WideStrings können z.B. Strings mit bis zu ca. 2^30 Zeichen enthalten. Und wenn du dann noch ein Interface verwendest, hast du eine schöne Schnittstelle.

BastiFantasti 6. Dez 2023 14:02

AW: Speicherproblem mit Objekten in DLL
 
Oh, das war ein Missverständnis.
Der Destruktor der Klasse, der das Objekt freigibt wird natürlich durchlaufen.
Nur die DLL wird nicht freigegeben (kein PROCESS_DETACH)

Also Objekt auf (create) - verwenden - Objekt zu (freeandnil)
Der Klassendestruktor wird auch durchlaufen und die enthaltenen TList Objekte werden korrekt freigegeben.

Ich habe jetzt noch etwas weiter recherchiert und habe gesehen, dass es mit der Objektdeserialisierung zusammenhängen muss.
FastMM4 zeigt mir unzählige Elemente an die noch offen sind, wenn die Anwendung beendet wird (obwohl die Objekte freigegeben sind).

Erschwerend kommt hinzu, dass diese Aufrufe innerhalb eines TThreads erfolgen. Eventuell gibt es auch hier Probleme mit der Speicherverwaltung / Freigabe.

Ich habe eine Test DLL gebaut, wo nur eine Funktion exportiert wird, die genau die gleiche Funktionalität abbildet wie oben beschrieben (Objekt auf, verwenden, zu)

Da tritt dieses Speicherleck nicht auf.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:04 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz