Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Verständnisfrage Memory-Leak einfacher String (https://www.delphipraxis.net/120322-verstaendnisfrage-memory-leak-einfacher-string.html)

Pfoto 9. Sep 2008 09:21


Verständnisfrage Memory-Leak einfacher String
 
Hallo zusammen,

ich habe mir angewöhnt immer mit
Delphi-Quellcode:
ReportMemoryLeaksOnShutdown := (DebugHook <> 0);
zu arbeiten.

Neuerdings bekomme ich nach Programmende manchmal, also unter
noch ungeklärten Bedinungen die Meldung, dass ein kleines
Speicherloch vorhanden ist und die Ergänzung "String".

Ich dachte immer, die Freigabe von Strings würde Delphi automatisch
erledingen, deshalb kann ich mir nicht erklären, wieso diese
Meldung überhaupt angezeigt wird (und ich habe auch keine Hoffung,
dieses Leck zu finden, denn mir fehlt einfach der Ansatzspunkt).



Könnt ihr mir da genaueres zu sagen?

Dank und Gruß
Jürgen

littleDave 9. Sep 2008 11:06

Re: Verständnisfrage Memory-Leak einfacher String
 
Delphi gibt die Strings an sich schon frei, sobald du aber mit Pointern auf Strings arbeitest, wirds haarig.

Mit folgendem Code bekommt man leicht ein Memory-Leak, obwohl man im OnDestroy die Pointer wieder freigibt.
Delphi-Quellcode:
var
  aList : TList;

procedure TForm1.FormCreate(Sender: TObject);
var p: PString;
    i: integer;
begin
  aList := TList.Create;

  for i:=0 to 10 do
  begin
    New(p);
    p^ := 'Test - 123';
    aList.Add(p);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var p: PString;
    i: integer;
begin
  for i:=0 to aList.Count-1 do
  begin
    p := aList[i];
    // mit Dispose wird zwar der Pointer wieder freigegeben, aber
    // der Inhalt ('Test - 123') vom Anfang wird nicht wieder
    // Freigegeben.
    Dispose(p);
  end;
  aList.Clear;
  aList.Free;
end;
Das Memory-Leak kann man umgehen, wenn man z.B. vor dem Dispose(p) in Zeile 28 folgende Zeile einfügt
Delphi-Quellcode:
{ ... }
    p^ := ''; // hiermit wird der String an sich wieder freigegeben
    Dispose(p);
  end;
{ ... }
Allgemein hat Delphi auch eine Funktion dafür: Finalize();
Aus der Delphi-Hilfe:
Zitat:

procedure Finalize(var V [; Count: Integer] );

Beschreibung
Finalize sollte nur in Delphi-Quelltext verwendet werden, in dem eine dynamisch erstellte Variable nicht mit der Prozedur Dispose freigegeben wird. Der von dynamische Arrays belegte Speicher kann mit der Prozedur Dispose nicht freigegeben werden. Dynamische Arrays müssen dazu an Finalize übergeben werden.
Beim Freigeben von globalen Variablen, lokalen Variablen, Objekten und dynamischen Variablen mit Dispose generiert der Compiler Programmcode, um alle in der Variablen enthaltenen langen Strings, Varianten und Schnittstellen zusammen mit der Instanz zu finalisieren.
Wenn auf eine dynamische Variable folgende Bedingungen zutreffen
  • Die Variable wird nicht mit der Standardprozedur Dispose (sondern z.B. mit FreeMem) freigegeben.
  • Die Variable enthält lange Strings, Varianten und Schnittstellen, die nicht alle leer sind bzw. den Wert Unassigned haben
Finalize setzt einfach alle langen Strings auf einen leeren Wert und alle Varianten und Schnittstellen auf Unassigned und sorgt somit für die ordnungsgemäße Freigabe des betreffenden Speichers.
Werden mehrere Variablen in einem zusammenhängenden Speicherblock freigegeben (z.B. ein dynamisches String-Array), kann der optionale Parameter Count angegeben werden, um alle Variablen in einer Operation zu deinitialisieren.
Enthält die als Parameter an Finalize übergebene Variable keine langen Strings, Varianten oder Schnittstelle entfernt der Compiler den Aufruf und generiert keinen Code.
Das ist jetzt nur eine Beschreibung, wie mir Strings Memory-Leaks entstehen können.

Pfoto 9. Sep 2008 11:14

Re: Verständnisfrage Memory-Leak einfacher String
 
Danke für Deine ausführliche Beschreibung,
habe auf jeden Fall was dazugelernt.

Ich arbeite zwar selbst nicht mit Pointern auf Strings,
aber vielleicht ist eine meiner Fremd-Komponenten die
Ursache. Schade, dass ich es bis jetzt nicht gezielt
reproduzieren konnte, dann wäre ich einen Schritt weiter.

Gruß
Jürgen

hanspeter 9. Sep 2008 12:21

Re: Verständnisfrage Memory-Leak einfacher String
 
Zitat:

Zitat von Pfoto
Danke für Deine ausführliche Beschreibung,
habe auf jeden Fall was dazugelernt.

Ich arbeite zwar selbst nicht mit Pointern auf Strings,
aber vielleicht ist eine meiner Fremd-Komponenten die
Ursache. Schade, dass ich es bis jetzt nicht gezielt
reproduzieren konnte, dann wäre ich einen Schritt weiter.

Gruß
Jürgen

VST - virtualStringTree ist ein üblicher Kandidat für diese Art von Speicherleaks.
Ist aber egal, da der Speicher mit Programmende ohnehin freigegeben wird.

Gruß Peter

Tyrael Y. 9. Sep 2008 12:41

Re: Verständnisfrage Memory-Leak einfacher String
 
Zitat:

Zitat von hanspeter

VST - virtualStringTree ist ein üblicher Kandidat für diese Art von Speicherleaks.
Ist aber egal, da der Speicher mit Programmende ohnehin freigegeben wird.

Gruß Peter

Nicht VST ist der schlimme Finger dabei, sondern derjenige, der es benutzt.

Hat man z.B. als Datenstruktur einen Record mit Strings als Felder, dann muss man diese Strings bei der Freigabe auf einen Leerstring setzen.

xaromz 9. Sep 2008 13:14

Re: Verständnisfrage Memory-Leak einfacher String
 
Hallo,
Zitat:

Zitat von Tyrael Y.
Hat man z.B. als Datenstruktur einen Record mit Strings als Felder, dann muss man diese Strings bei der Freigabe auf einen Leerstring setzen.

der korrekte Weg hierfür wäre wohl Delphi-Referenz durchsuchenFinalize().

Gruß
xaromz

Tyrael Y. 9. Sep 2008 13:18

Re: Verständnisfrage Memory-Leak einfacher String
 
Ok für dynamische Arrays, was ein String ja auch ist, ist dies vielleicht doch die bessere Wahl.
Ich habe es ehrlich gesagt bisher auf einen Leerstring gesetzt und hatte auch keine Leaks mehr.

littleDave 9. Sep 2008 13:18

Re: Verständnisfrage Memory-Leak einfacher String
 
Zitat:

Zitat von xaromz
der korrekte Weg hierfür wäre wohl Delphi-Referenz durchsuchenFinalize().

Siehe mein Post (#2) :zwinker:


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