![]() |
Dispose = Exception, kein Dispose = Memory Leak
Liste der Anhänge anzeigen (Anzahl: 1)
Die Themen Callback und Pointer auf Records wurden hier ja schön öfter diskutiert.
Ich habe das Prinzip aber offensichtlich immer noch nicht ganz verstanden. Folgendes Problem: Ich fordere in der aufrufenden Prozedur mit new(PointerAufRecord) Speicher an und übergebe diesen Pointer an die empfangende Routine. Dort muss ich den Speicher doch mit Dispose (PointerAufRecord) wieder freigeben, dachte ich ... Dieses Prinzip verwende ich zum Datenaustausch zwischen einer Clientapplikation und einer DLL, die als API für Drittanbieter dienen soll. Irgendwie klappt es mit dem Dispose nicht so, wie ich es gerne hätte. Wenn ich aus der Client-Applikation eine DLL Funktion (z.B. Register_ClientApplication(aRecord:PTRecord) ) aufrufe, und dort den Speicher von TRecord mit Dispose freigebe, dann gibt es eine Exception beim Beenden des Programmes. Wenn ich nach diesem Prinzip Daten in die Gegenrichtung (DLL > Clientanwendung) via Callback Funktion transportiere und den Speicher in der Client-Anwendung mit Dispose freigenen möchte, dann gibt es eine Exception beim Aufruf von Dispose. Lasse ich das Dispose in der DLL und in der Anwendung weg, dann "läuft alles super". Wäre da nicht das "kleine" Problem, dass der Speicher nicht freigegeben wird .... :roll: Ich habe ein kleines Spielprojekt angehängt. Werft ihr bitte mal einen Blick drauf ? Aufruf
Delphi-Quellcode:
DLL Funktion
procedure Register_API( const Servername:String );
begin ApiRegisterInfoRec := new(PTApiRegisterInfoRec); // Record füllen ApiRegisterInfoRec.Servername := Servername; // Callback Prozeduren übergeben ApiRegisterInfoRec.OnState := @OnGetApiState; ApiRegisterInfoRec.OnError := @OnGetApiError; // DLL Register_ClientApplication aufrufen Register_ClientApplication(ApiRegisterInfoRec); // DLL räumt den Speichern von ApiInitRec end;
Delphi-Quellcode:
function Register_ClientApplication ( aApiRegisterInfo : PTApiRegisterInfoRec):bool; stdcall;
begin try // Callback Funktionen initialisieren @Callback_OnState := @aApiRegisterInfo.OnState; @Callback_OnError := @aApiRegisterInfo.OnError; // Infos aus ApiRegisterInfo übernehmen PipeServername := aApiRegisterInfo.Servername; // Speicher von aApiRegisterInfo räumen // Dispose geht nicht. Exception beim Beenden der Client-Applikation // Dispose(aApiRegisterInfo); Registered := true; except on e:exception do begin registered := false; if assigned(Callback_OnError) then OnSendError(1001,esClientAPI,e.Message); raise exception.create('Fatal: Register_ClientApplication'+#13#10+e.Message); end; end; result := registered; // mit aktuellem Status antworten OnSendState(registered, true,101, PipeServername); end; |
Re: Dispose = Exception, kein Dispose = Memory Leak
Achtung! du hast zwei speichermanager und kannst nicht einfach Speicher in dem einen Programm anfordern und in dem anderen freigeben.
Warum nimmst du das Dispose nicht auch in die aufrufende Exe? Edit: Es sollte auch so gehen (ganz ohne dispose und new).. Aufruf:
Delphi-Quellcode:
procedure Register_API( const Servername:String );
var ApiRegisterInfoRec:TApiRegisterInfoRec; begin // Record füllen ApiRegisterInfoRec.Servername := Servername; // Callback Prozeduren übergeben ApiRegisterInfoRec.OnState := @OnGetApiState; ApiRegisterInfoRec.OnError := @OnGetApiError; // DLL Register_ClientApplication aufrufen Register_ClientApplication(@ApiRegisterInfoRec); end; |
Re: Dispose = Exception, kein Dispose = Memory Leak
Wenn dynamisch belegter Speicher zwischen verschiedenen Modulen ausgetauscht wird, muss immer das Modul den Speicher freigeben, das ihn auch belegt hat. Alternativ kannst du sowohl im Programm als auch in der DLL als erstes die Unit ShareMem einbinden - das ersetzt den Standard-Speichermanager der Delphi-Runtime durch einen, der auch über Modulgrenzen funktioniert. Dann muss zusammen mit dem Programm allerdings noch die borlndmm.dll installiert werden, die diesen Speichermanager enthält.
Ohne ShareMem ist es so richtig:
Delphi-Quellcode:
Stefan
procedure Register_API( const Servername:String );
begin ApiRegisterInfoRec := new(PTApiRegisterInfoRec); // Record füllen ApiRegisterInfoRec.Servername := Servername; // Callback Prozeduren übergeben ApiRegisterInfoRec.OnState := @OnGetApiState; ApiRegisterInfoRec.OnError := @OnGetApiError; // DLL Register_ClientApplication aufrufen Register_ClientApplication(ApiRegisterInfoRec); // Speicher von ApiInitRec aufräumen Dispose(ApiRegisterInfoRec); end; |
Re: Dispose = Exception, kein Dispose = Memory Leak
Ich habe jetzt das new() und Dispose() weggelassen und als Parameter "aRecord:TeinRecord" anstatt "aRecord:PTeinRecord" übergeben.
Sieht so aus als hätte ich mir das Leben zu schwehr gemacht. Es funktioniert soweit. Sharemem will ich bewusst nicht benutzen, weil die API kompatibel mit C++ sein muss. Danke. |
Re: Dispose = Exception, kein Dispose = Memory Leak
Du kannst auch LocalAlloc und LocalFree verwenden. Ich habs zwar nie wirklich direkt ausprobiert.
Aber es gibt WinApi funktionen, die rufen LocalFree oder LocalAlloc von dem Speicher auf, den ich selbst durch LocalAlloc oder LocalFree erstellt oder zerstört habe. Die WinAPI ist ja selbst in DLLs. |
Re: Dispose = Exception, kein Dispose = Memory Leak
Zitat:
|
Re: Dispose = Exception, kein Dispose = Memory Leak
Also der beste Zweck ist bei Callback Funktionen (z.b. auch bei COM).
Wenn eine Funktion als Callback aufgerufen wird und ein Speicher erstellen soll, dann sollte er von der aufzurufende Fkt gelöscht werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:46 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz