Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Memory Leak bei TJsonObject (https://www.delphipraxis.net/209573-memory-leak-bei-tjsonobject.html)

Kostas 23. Dez 2021 13:08

Memory Leak bei TJsonObject
 
Hallo Zusammen,

das Problem vorab: beim Zuweisen von
Delphi-Quellcode:
LResponse
entsteht ein Memory Leak.

Über die folgende Methode rufe ich per indy ein JSON response ab. Der Inhalt ist ein neues Token welches abgelaufen ist ab.
Es funktioniert einwandfrei. Wenn ich jedoch die Anwendung beende, wird ein Memory Leak signalisiert da ich
Delphi-Quellcode:
Application.MainFormOnTaskbar := True;
in der Projektdatei aktiviert habe.
Ich habe Schrittweise alles auskommentiert und die Stelle lokalisieren können die dafür verantwortlich ist. Es ist die Zuweisung von
Delphi-Quellcode:
LResponse

Delphi-Quellcode:
procedure TdmCleverReach.RefreshToken;
var LResponse: TJsonObject;
    LResponseStream: TBytesStream;
    FormData: TidMultiPartFormDataStream;
begin

  Formdata := TIdMultiPartFormDataStream.Create;
  Formdata.AddFormField('grant_type', 'refresh_token');
  Formdata.AddFormField('refresh_token', INIRefreshToken);
  Formdata.AddFormField('client_id', INIClientID);
  Formdata.AddFormField('client_secret', INIClientSecret);
  FormData.Position := 0;

  LResponseStream := TBytesStream.Create;
  LResponse := TJsonObject.Create;
  try
    IdhttpToken.Request.CustomHeaders.Clear;
    IdhttpToken.Request.CustomHeaders.AddPair('Content-Type','multipart/form-data');
    try
      IdhttpToken.Post(INITokenURL,FormData,LResponseStream);
      LResponseStream.Position := 0;

      //Hier scheint der Memory Leak zu entstehen, aber warum?
>>>>     LResponse := TJsonObject.ParseJSONValue(LResponseStream.Bytes, 0, LResponseStream.Size) as TJsonObject;


    LResponseStream.SaveToFile(PrgPath + '\ResponseStream.JSON');

  finally
    Formdata.Free;
    LResponse.Free;
    LResponseStream.Free;
  end;
end;
Was mache ich falsch?

Gruß Kostas

peterbelow 23. Dez 2021 13:14

AW: Memory Leak bei TJsonObject
 
Zitat:

Zitat von Kostas (Beitrag 1499627)
Hallo Zusammen,

das Problem vorab: beim Zuweisen von
Delphi-Quellcode:
LResponse
entsteht ein Memory Leak.

Ich habe Schrittweise alles auskommentiert und die Stelle lokalisieren können die dafür verantwortlich ist. Es ist die Zuweisung von
Delphi-Quellcode:
LResponse

Delphi-Quellcode:
procedure TdmCleverReach.RefreshToken;
var LResponse: TJsonObject;
    LResponseStream: TBytesStream;
    FormData: TidMultiPartFormDataStream;
begin

  Formdata := TIdMultiPartFormDataStream.Create;
  Formdata.AddFormField('grant_type', 'refresh_token');
  Formdata.AddFormField('refresh_token', INIRefreshToken);
  Formdata.AddFormField('client_id', INIClientID);
  Formdata.AddFormField('client_secret', INIClientSecret);
  FormData.Position := 0;

  LResponseStream := TBytesStream.Create;
  LResponse := TJsonObject.Create;
Die hier erzeugte Instanz wird nie verwendet und auch nie freigegeben.

Weiter unten überrschreibt dein Kode

Delphi-Quellcode:
   LResponse := TJsonObject.ParseJSONValue(LResponseStream.Bytes, 0, LResponseStream.Size) as TJsonObject;
das Objekt.

Kostas 23. Dez 2021 13:31

AW: Memory Leak bei TJsonObject
 
oh, genau das habe ich übersehen dass ParseJSONValue ein neues Object erzeugt.

herzlichen Dank.

himitsu 23. Dez 2021 13:42

AW: Memory Leak bei TJsonObject
 
Und jetzt sag blos, dass es dir der Compiler nicht vorher gesagt hat?

Kostas 23. Dez 2021 14:08

AW: Memory Leak bei TJsonObject
 
Nein, von Compiler habe ich keine Warnung oder Hinweis bekommen.
Ist das einstellbar in den Optionen?

Gruß Kostas

Uwe Raabe 23. Dez 2021 14:16

AW: Memory Leak bei TJsonObject
 
Zitat:

Zitat von himitsu (Beitrag 1499634)
Und jetzt sag blos, dass es dir der Compiler nicht vorher gesagt hat?

Das ist gar nicht mal so sicher. Schließlich könnte ja die zuerst erzeugte Instanz bei einer Exception im finally freigegeben werden und würde somit tatsächlich verwendet.:-D

Incocnito 23. Dez 2021 14:28

AW: Memory Leak bei TJsonObject
 
In der Tat ... entweder musst du vor der neu-Zuweisung das "alte" Objekt freigeben, oder du ziehst das Free aus dem unteren finally weiter nach oben.
Delphi-Quellcode:
procedure TdmCleverReach.RefreshToken;
var LResponse: TJsonObject;
    LResponseStream: TBytesStream;
    FormData: TidMultiPartFormDataStream;
begin

  Formdata := TIdMultiPartFormDataStream.Create;
  Formdata.AddFormField('grant_type', 'refresh_token');
  Formdata.AddFormField('refresh_token', INIRefreshToken);
  Formdata.AddFormField('client_id', INIClientID);
  Formdata.AddFormField('client_secret', INIClientSecret);
  FormData.Position := 0;

  LResponseStream := TBytesStream.Create;
  try
    IdhttpToken.Request.CustomHeaders.Clear;
    IdhttpToken.Request.CustomHeaders.AddPair('Content-Type','multipart/form-data');
    try
      IdhttpToken.Post(INITokenURL,FormData,LResponseStream);
      LResponseStream.Position := 0;

      //Hier scheint der Memory Leak zu entstehen, aber warum?
      LResponse := TJsonObject.ParseJSONValue(LResponseStream.Bytes, 0, LResponseStream.Size) as TJsonObject;
      try
        // whatever
      finally
        LResponse.Free;
      end;
      LResponseStream.SaveToFile(PrgPath + '\ResponseStream.JSON');
    finally
      // ...
    end;
  finally
    Formdata.Free;
    LResponseStream.Free;
  end;
end;

DeddyH 23. Dez 2021 14:35

AW: Memory Leak bei TJsonObject
 
Delphi-Quellcode:
  LResponse := nil;
  try
    ...
    LResponse := TJsonObject.ParseJSONValue(LResponseStream.Bytes, 0, LResponseStream.Size) as TJsonObject;
  finally
    LResponse.Free;
    ...
  end;
Da genügt dann ein Ressourcenschutzblock.

himitsu 23. Dez 2021 14:44

AW: Memory Leak bei TJsonObject
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1499641)
Das ist gar nicht mal so sicher. Schließlich könnte ja die zuerst erzeugte Instanz bei einer Exception im finally freigegeben werden und würde somit tatsächlich verwendet.:-D

Aber nur wenn es knallt,
allerdings sollte bei der zweiten Zuweisung eigentlich eine Warnung kommen, denn ohne knallen würde der erste Wert niemals verwendet.

Kostas 23. Dez 2021 16:03

AW: Memory Leak bei TJsonObject
 
LResponse wird vorher NICHT erzeugt!

So habe ich es jetzt umgesetzt.

Delphi-Quellcode:
    try
      LResponse := TJsonObject.ParseJSONValue(LResponseStream.Bytes, 0, LResponseStream.Size) as TJsonObject;

      if Assigned(LResponse) then
      begin
        LResponse.TryGetValue<String>('access_token', access_token);
        LResponse.TryGetValue<String>('refresh_token', refresh_token);
        LResponse.TryGetValue<integer>('expires_in', expires_in);
        LResponse.Free;
      end;
    except
      // Fehlerbehandlung.
    end;
Vielen lieben Dank und frohe Weihnachten an alle.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:49 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