Einzelnen Beitrag anzeigen

Benutzerbild von littleDave
littleDave

Registriert seit: 27. Apr 2006
Ort: München
556 Beiträge
 
Delphi 7 Professional
 
#2

Re: Verständnisfrage Memory-Leak einfacher String

  Alt 9. Sep 2008, 11:06
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.
Jabber: littleDave@jabber.org
in case of 1 is 0 do external raise while in public class of object array else repeat until 1 is 0
  Mit Zitat antworten Zitat