Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi unverständlicher Memoryleak in Funktion (https://www.delphipraxis.net/207808-unverstaendlicher-memoryleak-funktion.html)

Maliko 5. Mai 2021 13:38

unverständlicher Memoryleak in Funktion
 
Moin,

ich verzweifle gerade an einem Memoryleak, bei dem ich nicht verstehe warum er entsteht. Und zwar habe ich folgende Funktion:

Delphi-Quellcode:
function TxxxManager.StringsToJSONArray(const Data: TStrings): TJSONArray;
var
  i: Integer;
begin
  Result := TJSONArray.Create;
  for i := 0 to Data.Count - 1 do
  begin
    Result.Add(Data[i]);
  end;
end;
Es handelt sich hierbei um eine ganz normale Funktion und keine Class-Function. Deleaker sagt mir jetzt dass in Zeile 5 und in Zeile 8 der Funktion jeweils ein Memoryleak sind (um genau zu sein durch die Objekte TJsonString, TJsonArray und TList<TJsonValue>).

Ich rufe diese Funktion aber über folgende Funktion auf:

Delphi-Quellcode:
function Global.Principals: TJSONArray;
var
  mManager : TxxxManager;
  mMandanten : TStringList;
begin
  mManager := TxxxManager.Create;

  try
    mMandanten := TMandantRepository.GetMandantenMitKonzern(cKONZERN_XXX);
    Result := mManager.StringsToJSONArray(mMandanten);
  finally
    FreeAndNil(mManager);
  end;
end;
Was ich jetzt nicht verstehe. Ich gebe mManager wieder frei. Müsste er dann nicht auch die Resultvariable und Abhängigkeiten davon wieder freigeben oder habe ich da gerade ein Verständnisproblem? Bei Klassenfunktionen umgehe ich das Problem indem ich den Result in eine globale Variable kippe, die dann als Result übergebe und über den Klassendesturktor dann die globale Variable (die selbstverständlich private ist) wieder freigebe. Aber bei einer normalen Funktion müsste ich mir diesen Teil doch eigentlich schenken können, da doch bei FreeAndNil auch die Results wieder freigegeben werden. Zumindest hab ich das bisher so verstanden.

Könnte mir da vielleicht jemand weiter helfen? Ich komme ursprünglich aus dem C#-Umfeld und da hatten wir nen Garbage-Collector, der sich um das alles gekümmert hat. Daher fehlen mir hier grad so ein wenig die Basics in der Speicherverwaltung, weil das ein Thema war, welches ich vor Delphi nicht berücksichtigen musste.

Vielen Dank schon einmal im Voraus.

Viele Grüße
Maliko

DeddyH 5. Mai 2021 13:43

AW: unverständlicher Memoryleak in Funktion
 
Das würde dann funktionieren, wenn TxxxManager.StringsToJSONArray nicht bei jedem Aufruf eine neue Instanz erzeugen würde, sondern eine Property von TxxxManager wäre, die bei jedem Aufruf nur neu befüllt wird. Natürlich muss das dahinterliegende Feld im Destruktor von TxxxManager aber wieder freigegeben werden.

[edit] Alternativ könnte TxxxManager aber auch eine Liste der erzeugten Instanzen pflegen als TObjectList<TJSONArray>. Bei jedem Aufruf von StringsToJSONArray wird das Result dann der Liste hinzugefügt und die Liste im Destruktor wieder freigegeben. Das setzt aber voraus, dass danach nirgends mehr auf so ein Result zugegriffen wird, egal wo. [/edit]

himitsu 5. Mai 2021 13:43

AW: unverständlicher Memoryleak in Funktion
 
Da StringsToJSONArray und Principals eine neu erstellte Komponente raus geben, muß dass dann der freigeben, welcher Principals aufgerufen hat.


Wenn da der Manager hier das Result nicht freigibt, gibt es da kein Problem, weil unabhängig.

Aber wer gibt mMandanten wieder frei?
Oder ist diese Liste z.B. ein Signleton, die intern verwaltet und von der Kompontene später freigegeben wird?

Klaus01 5. Mai 2021 13:45

AW: unverständlicher Memoryleak in Funktion
 
.. Du erstellst in der ersten Funktion eine Instanz einer Klasse.
Die übergibst Du in der zweiten Funktion dem result der Funktion.
Wo die Instanz terminiert wird ist hier nicht ersichtlich.
Erstellt wird sie in Funktion 1, daher wird auch dort der Leak gemeldet.

Nein result von Funktionen werden beim Beenden der Funktion nicht freigegeben - wo würde das auch hinführen?

Grüße
Klaus

Maliko 5. Mai 2021 13:57

AW: unverständlicher Memoryleak in Funktion
 
Zitat:

Zitat von Klaus01 (Beitrag 1488651)
.. Du erstellst in der ersten Funktion eine Instanz einer Klasse.
Die übergibst Du in der zweiten Funktion dem result der Funktion.
Wo die Instanz terminiert wird ist hier nicht ersichtlich.

Hmm an diesen Punkt habe ich noch gar nicht gedacht. Es handelt sich bei dem Projekt um eine REST-Schnittstelle welche über einen DataSnap-Rest-Server läuft. Die Global-Unit ist dabei die Methodunit, in welcher die Endpunkte definiert werden. Da das ganze allerdings ein Windowsservice ist und sich so mit Deleaker nicht übewachen lässt umgehe ich den Service gerade und rufe die Endpunkte gerade direkt auf.

Sprich es kann sein, dass dieser Memoryleak eigentlich gar nicht existiert, da der DataSnap-Server sich um das Disposing des Global-Results kümmert?

himitsu 5. Mai 2021 14:01

AW: unverständlicher Memoryleak in Funktion
 
Ob DataSnap die Objekte freigibt, welche als Result aus Servermethoden rausgehen, bzw. aus Client-Methoden zurück zum Server, das ist eine Einstellung.

Ich glaub in den automatisch generierten Server-/Client-Klassen gab es eine Variable in der Server-Klasse, welche dieses Free regelt.
Per Standard macht DataSnap hier aber das Free, da man als Entwickler keinen Zugriff darauf hat, wann die Übertragung abgeschlossen ist, nachdem die Methode verlassen wurde.

Maliko 5. Mai 2021 14:03

AW: unverständlicher Memoryleak in Funktion
 
Da ich da keine Einstellung verändert habe wird sich DataSnap dann wohl darum kümmern. Muss ich gleich mal ausprobieren. Ich starte den Service mal Lokal, setz nen Request ab und beobachte die Arbeitsspeicherveränderung im Task. Wenn sich der Arbeitsspeicher nicht verändert, dann ist es kein Leak.

himitsu 5. Mai 2021 14:04

AW: unverständlicher Memoryleak in Funktion
 
Du kannst ja im Destroy deines Objektes, welches raus geht, die Freigabe debuggen/loggen.

Falls es sich dort nicht Debuggen oder diese Klasse sich nicht ableiten lässt,
dann kann man sich auch über den TVirtualMethodInterceptor dranhängen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:52 Uhr.

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