![]() |
SetLength(dyn. array, 0) vs. Finalize() vs. nil
Hallo Community,
Ich habe mal im Forum rechergiert, welche Möglichkeiten es gibt, dyn. arrays freizugeben. Dabei bin ich auf die o.g. Prozeduren bzw. nil gestoßen und bin jetzt leicht verwirrt. Ich zitiere einfach mal die verschiedenen Aussagen: Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Wie sollte ich jetzt die beiden dyn. arrays sauber freigeben, sodass der gesamte Speicherbereich wieder an Windows übergeben wird?
type
TStringArray = array of String; var Partition : array of TTreeNode; Dirs : TStringArray; [...] SetLength(Partition,10); SetLength(Dirs,3); [...] // Freigeben beider dyn. arrays Btw: Wie müsste ich ein array of "record" korrekt freigeben, wenn dieser u.a. Short- bzw. LongStrings (= unbegrenzte Angabe), Integers und TreeNodes enthalten würde? |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
Zum Thema: Ich kann zu meiner vorherigen Aussage trotzdem nur nochmals ausführen, was ich festgestellt habe: 1. Dynamischen Arrays einfach NIL zuweisen gibt diese nicht sauber frei und werden als verlorener Speicher bei Speichertestern ausgegeben (Delphi 4 und Delphi 5) 2. lokale dynamische Arrays in Proceduren hinterlassen !sporadisch! Speicherlecks, wenn nach dem SetLength() kein Finalize() kommt (Delphi 4) 3. direktes anwenden von Finalize auf ein dynamisches Array führt zu einer ungenügenden Array Freigabe, es bleiben im Schnitt 8 Bytes nicht freigegeben zurück (Delphi 5). Bei höheren Delphiversionen mag das alles klappen und ein vernünftiger Weg sein. |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Also nach deiner Auffassung sollte ich bei dem Beispiel die dyn. arrays so freigeben?
Delphi-Quellcode:
Muss ich nicht die einzelnen TreeNodes aus dem array "Partition" seperat freigeben oder übernimmt gerade Finalize() diese Aufgabe für mich?
SetLength(Partition,0);
SetLength(Dirs,0); Finalize(Partition); Finalize(Dirs); |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Ein dynamisches Array mit dem base type TTreeNode ist recht ungewöhnlich. Grundsätzlich lebt ein TTreeNode in der Obhut von TTreeNodes und dieser Container verwaltet die Nodes von der Wiege bis zur Bahre. Finalize(), angewandt auf das dynamische array, weiß nichts von diesem Doppelleben der Nodes und darf auch gar nichts darüber wissen.
Grüße vom marabu |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Jo, deine Aussage war richtig. Es ist wirklich ungewöhnlich und sinnlos, solch ein array zu deklarieren, wie ich in meinem Code bemerkt habe. Habe das jetzt korrigiert.
Zu Finalize(): Diese Prozedur wird also nur auf Variablen mit undefinierbarer Länge angewandt, wie z.B. auf long-strings, variants usw.? D.h. es gibt keinen Grund, diese Prozedur auf array of Extended oder array of String[200] bzw. Shortstring loszulassen, richtig? Noch mal zu records:
Delphi-Quellcode:
Da in diesem record eine Variable mit undefinierter Länge (= String) enthalten ist, müsste ich diesen doch beim Freigeben des arrays mit Finalize() leeren, oder? Und wenn ja, wie genau?
type
PGroupData = ^TGroupData; TGroupData = record GroupID : Word; ShouldExpand : Boolean; S : String; end; var TestArrayT : array of TGroupData; // wird eher selten benutzt, nicht wahr? TestArrayP : array of PGroupData; Wenn ich jetzt falsch liege, erklärt mir bitte das Gegenteil mithilfe der Beipiele. Das hilft mir ungemein. |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
Zitat:
Delphi-Quellcode:
type
PGroupData = ^TGroupData; TGroupData = record GroupID : Word; ShouldExpand : Boolean; S : String; end; var TestArrayT : array of TGroupData; // wird eher selten benutzt, nicht wahr? TestArrayP : array of PGroupData; Zitat:
Für deinen zweiten Array-Typ bin ich im Augenblick überfragt. Ich vermute sehr stark, dass keine Finalisierung statt finden wird, aber ich müsste es untersuchen um sicher zu sein. marabu |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Vielen Dank für die detailierten und klärenden Erläuterungen, Muetze1 und marabu.
Zusammenfassend kann man also sagen: Mit SetLength initialisierte dyn. arrays sollten mit (in der Reihenfolge) 1.) SetLength(array, 0); und 2a.) Finalize(array); bzw. 2b.) Finalize(array, Length(array)); freigegeben werden. 2a) wird benutzt, wenn ein array of vordefinierte Typen (= string, Integer, Real, Boolean usw.) verwendet wird. 2b) wird benutzt, wenn ein array of TRecord verwendet wird. Erbitte Bestätigung für diese Zusammenfassung. Danke. |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Ich sehe keinen Interpretationsspielraum in dieser Frage. "Dynamische Typen" sind die internen Typen LongString, WideString, Variant, Array, Record, Interface und DynArray. Wenn v eine Variable ist und ihr Typ zu den zuvor genannten zählt, dann ist Finalize(v) bzw. Finalize(v, Length(v)) angesagt. Bei Arrays folgt dann SetLength(v, 0), bei den anderen Typen v := nil - so ist man auf der sicheren Seite.
marabu |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Ok, ok...
eins noch: Gerade an dieser Stelle kreuzen sich 2 Meinungen: Zitat:
Zitat:
|
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Hallo Nogge,
wenn SetLength(v, 0) zuerst ausgeführt wird, dann kommt Finalize(v, Length(v)) doch nach der Feier.
Delphi-Quellcode:
Sonntagsgrüße vom marabu
type
TItem = packed record Name: string; Amount: integer; end; var Items: array of TItem; i: integer; begin // es werden 3 mal 8 Byte vom heap besorgt SetLength(Items, 3); // die einzelnen Items werden initialisert for i := Low(Items) to High(Items) do with Items[i] do begin // der pointer "Name" wird auf einen dynamischen // Speicherblock gesetzt, der 6 Byte Nutzdaten zzgl. // Verwaltungsinformationen (Längenzähler, term char, etc. // umfasst. Name := 'Name-' + IntToStr(Succ(i)); // nativer Datentyp, kein heap beteiligt Amount := Succ(Random(5)); end; end; // Alle Zeiger "Name" werden auf nil gesetzt // der garbage collector beobachtet den auf // 0 gehenden refence count und deallokiert // den von den strings auf dem heap belegten Speicher Finalize(Items, Length(Items)); // Die 3 * 8 Byte müssen auch noch an den heap // zurückgegeben werden. SetLength(Items, 0); end; |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
Das hier diskutierte kommt mir mehr so vor:
Delphi-Quellcode:
So jetzt kann ich mir sicher sein, dass MyObj auch wirklich freigegeben wurde.
MyObj := TMyObj.Create;
... MyObj.Free; MyObj := nil; MyObj.Free; MyObj := nil; MyObj.Free; MyObj := nil; MyObj.Free; MyObj := nil; MyObj.Free; MyObj := nil; MyObj.Free; MyObj := nil; Finalize muss man nur Aufrufen, wenn man auf New und Dispose bei Zeigern auf Records verzichtet, also die Compile-Magic umgeht.
Delphi-Quellcode:
Bei dynamischen Arrays übernimmt der Compiler genauso wie bei Strings automatisch die Initialisierung und Finalisierung. Da muss man nichts selbst einfügen. Das Delphi 4 da noch einen Bug hat, der von einem Update dann aber behoben wurde (wenn ich mich recht erinnere), heißt noch lange nicht, dass Delphi 5, 6, 7, 8, 2005 diesen Bug auch haben.
var P: PMyRec;
begin New(P); ... Finalize(P); FreeMem(P); // Statt Dispose gleich direkt freigeben, macht zwar keinen Sinn, aber wers so will end; |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Moin, Ich habe deinen Satz (mit "Feier" usw.) zwar nicht verstanden, aber dafür den Code :-D Nur woher weiß SetLength(Items,0) anfangs, dass genau 8 Bytes pro TItem benötigt werden? Entstehen diese 8 bzw. 7 Bytes nicht erst bei der Zuweisung der einzelnen Strings?
@jbg: Und noch eine andere Meinung...Ich habe ja extra die unterschiedlichen Ansichten am Anfang zitiert, um meine Verwirrung darzustellen. Einer der Profis meint dies, der andere dementiert das wieder und interpretiert etwas anderes in die Delphi-Hilfe hinein... |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
Das gilt (so weit ich weiß) sogar für verschachtelte Typen, also für Arrays von einem Record das jeweils wieder ein dynamisches Array enthält. |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
Ausgelöst durch den Beitrag von jbg habe ich mich mit deinem TestArrayT und TestArrayP intensiver beschäftigt. Zitat:
Zitat:
In meinem vorigen Beitrag habe ich versucht zu erklären, warum ein Finalize(v, 10) nach einem SetLength(v, 0) fehl am Platze ist (wer zu spät kommt, der kommt nach der Feier - alte Redensart). Das Beispiel ist frei von Seiteneffekten und hoffentlich leicht nachvollziehbar gewesen. Niemand sollte sich verplichtet fühlen dem Beispiel zu folgen, wenn er es nicht verstanden hat oder gar einen besseren Weg kennt. Freundliche Grüße vom marabu PS: Auf einen Fehler von mir hat mich tommie-lie per PN aufmerksam gemacht: Zitat:
Danke, Thomas (tommie-lie). |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
Zitat:
|
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
|
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
@jbg: Jep, das ist ja auch klar. Ich gebe ja durch SetLength() nur den Speicher für die Pointer frei, nicht aber den Speicherbereich, den der record einnimmt.
@marabu: Es handelte sich hier um ein Missverständnis. Ich dachte anfangs, SetLength() "weiß" bereits VOR der der Zuweisung der einzelnen string-Variablen, dass diese mit 6 Bytes Inhalt (="Name-3") + 1 Byte string-Zeiger + Byte Integer-Wert aus dem record initialisiert werden. Meine völlig falsche Selbsterklärung, wie diese 8 Bytes zustande kommen, gehört nun der Vergangenheit an und ich weiß es jetzt besser. Vielen Dank an alle, die meine Verwirrungen beseitigen und mir beim Erweitern der Grundkenntnisse helfen konnten! Bis zum nächsten Problem, Nogge :wink: |
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Zitat:
Zitat:
|
Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil
Ja.
Delphi-Quellcode:
function New(Size: Longint; TypeInfo: Pointer): Pointer;
begin GetMem(Result, Size); if Result <> nil then Initialize(Result, TypeInfo); end; procedure Dispose(P: Pointer; TypeInfo: Pointer); begin Finalize(P, TypeInfo); FreeMem(P); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:11 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