AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi SetLength(dyn. array, 0) vs. Finalize() vs. nil
Thema durchsuchen
Ansicht
Themen-Optionen

SetLength(dyn. array, 0) vs. Finalize() vs. nil

Ein Thema von Nogge · begonnen am 4. Nov 2005 · letzter Beitrag vom 6. Nov 2005
Antwort Antwort
Seite 1 von 2  1 2      
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#1

SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 4. Nov 2005, 22:45
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 von Muetze1:
Ich hatte früher öfters irgendwo und sporadisch Speicherlecks und z.T. Zugriffsverletzungen ohne Grund - bis ich diese beiden Funktionen eingesetzt habe. Zum grundlegenden Einsatz:

- Vor der Verwendung des Arrays einmalig Initialize() (also auch vor dem SetLength())
- Nach der Verwendung des Arrays einmalig Finalize() (also zuvor SetLength(arr, 0))
Zitat von sakura:
SetLength(MyFlexibleArray, 20); allocates an array of 20 reals, indexed 0 to 19. Dynamic arrays are always integer-indexed, always starting from 0.
Dynamic-array variables are implicitly pointers and are managed by the same reference-counting technique used for long strings. To deallocate a dynamic array, assign nil to a variable that references the array or pass the variable to Finalize; either of these methods disposes of the array, provided there are no other references to it. Dynamic arrays of length 0 have the value nil. Do not apply the dereference operator (^) to a dynamic-array variable or pass it to the New or Dispose procedure.
Zitat von Chewie:
Sie bewirken das gleiche, wobei die nil-Variante ein paar Takte schneller ist. Bei der Zuweisung an nil wird gleich DynArrayClear aufgerufen, bei der Variante mit SetLength wird erst DynArraySetLength aufgerufen, welches dann wiederum besagtes DynArrayClear aufruft.
Nach dem ganzen Hin- und Her: Nehmen wir mal zwei Beispiele:
Delphi-Quellcode:
type
  TStringArray = array of String;
var
  Partition : array of TTreeNode;
  Dirs : TStringArray;
  [...]
  SetLength(Partition,10);
  SetLength(Dirs,3);
  [...]
  // Freigeben beider dyn. arrays
Wie sollte ich jetzt die beiden dyn. arrays sauber freigeben, sodass der gesamte Speicherbereich wieder an Windows übergeben wird?
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?
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#2

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 14:29
Zitat von Nogge:
..., sodass der gesamte Speicherbereich wieder an Windows übergeben wird?
Nur eine kurze Anmerkung zu dieser Frage und nicht zum Problem an sich: Der Speicherbereich wird nicht an Windows sondern an den Heap zurück gegeben. Ob der Heap sich verkleinert und Teile an Windows zurück gibt, das hängt sehr stark vom verwendeten Speichermanager ab - die meisten verkleinern sich nicht mehr (schon als verwaltungstechnischen Gründen).

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.
  Mit Zitat antworten Zitat
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#3

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 15:18
Also nach deiner Auffassung sollte ich bei dem Beispiel die dyn. arrays so freigeben?
Delphi-Quellcode:
SetLength(Partition,0);
SetLength(Dirs,0);
Finalize(Partition);
Finalize(Dirs);
Muss ich nicht die einzelnen TreeNodes aus dem array "Partition" seperat freigeben oder übernimmt gerade Finalize() diese Aufgabe für mich?
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#4

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 15:45
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
  Mit Zitat antworten Zitat
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#5

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 16:21
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:
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;
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?
Wenn ich jetzt falsch liege, erklärt mir bitte das Gegenteil mithilfe der Beipiele. Das hilft mir ungemein.
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#6

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 16:56
Zitat von Nogge:
Zu Finalize(): Diese Prozedur wird also nur auf Variablen mit undefinierbarer Länge angewandt, wie z.B. auf long-strings, variants usw.?
Ich würde nicht von undefinierbarer Länge sprechen, sondern von speziellen dynamischen Variablen. In Delphi werden dynamische Variablen normalerweise mit New() und Dispose() verwaltet. Mit den long strings, den variants und den interfaces (die Aufzählung ist nicht vollständig) hat eine neue Klasse "dynamischer Variablen" in Object Pascal Einzug gehalten, bei der auch oft von compiler magic gesprochen wird. Es sind dynamische Variablen, bei denen nicht du es bist, der New() und Dispose() aufruft. Das Laufzeitsystem weiß, wann es Speicher braucht und wann es ihn wieder freigeben muss - wenn du ihm nicht in die Quere kommst.

Zitat von Nogge:
D.h. es gibt keinen Grund, diese Prozedur auf array of Extended oder array of String[200] bzw. Shortstring loszulassen, richtig?
Falsch, aber das müsstest du selbst erkennen, wenn du meinen Beitrag bis hierhin gelesen hast. Dynamische Arrays gehören halt auch zu dieser speziellen Variablen-Klasse.

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 von Nogge:
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?
Finalize(TestArrayT, Length(TestArrayT)) sorgt dafür, dass für alle Elemente deines Arrays die reference counts dekrementiert werden können und der garbage collector seines Amtes walten kann.

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
  Mit Zitat antworten Zitat
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#7

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 19:33
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.
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#8

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 19:52
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
  Mit Zitat antworten Zitat
Nogge

Registriert seit: 15. Jul 2004
336 Beiträge
 
Delphi 7 Professional
 
#9

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 5. Nov 2005, 23:08
Ok, ok...
eins noch: Gerade an dieser Stelle kreuzen sich 2 Meinungen:
Zitat von marabu:
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).
Zitat von Muetze1:
2. lokale dynamische Arrays in Proceduren hinterlassen !sporadisch! Speicherlecks, wenn nach dem SetLength() kein Finalize() kommt (Delphi 4).
Sry, wenn ich dich vllt nerve, aber kommt Finalize() jetzt hinter oder vor SetLength()?
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#10

Re: SetLength(dyn. array, 0) vs. Finalize() vs. nil

  Alt 6. Nov 2005, 07:46
Hallo Nogge,

wenn SetLength(v, 0) zuerst ausgeführt wird, dann kommt Finalize(v, Length(v)) doch nach der Feier.

Delphi-Quellcode:
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;
Sonntagsgrüße vom marabu
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:18 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