Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben? (https://www.delphipraxis.net/210690-warum-wird-eine-dynamisch-erzeugte-matrix-scheinbar-automatisch-freigegeben.html)

Andreas13 27. Mai 2022 16:51

Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Hallo Community,
ich erzeuge zur Laufzeit eine spezielle zweidimensionale dynamische Struktur: Eine dreieckige Matrix gemäß nachfolgendem Demo-Programm. Die Dreieckmatrix wird von der Procedure
Delphi-Quellcode:
Make_3EckMatrix(..)
erzeugt. Die Procedure
Delphi-Quellcode:
PrintMatrixX(..)
hilft Euch bei der simplen Visualisierung dieser Struktur.
Delphi-Quellcode:
program _3Eck_Matrix_2;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

Type
  TDynExtendedVektor = TArray<Extended>; // = Array of Extended;
  TMatrix           = Array of TDynExtendedVektor;

 
Procedure PrintMatrixX(CONST Matrix: TMatrix; Name: String); Overload;
// Nur zum Debuggen

VAR
  Zeile, Spalte, n_Zeilen, n_Spalten: Integer;

CONST
  Leer = '   ';
  Pad = 6;

Begin
  WriteLn;
  WriteLn(Name + '[', Low(Matrix), '..', High(Matrix), ' ; ', Low(Matrix[0]), '..', High(Matrix[0]), ']');
  WriteLn('--------------------------');

  n_Zeilen:= Length(Matrix);

  For Zeile:= 0 To n_Zeilen - 1 Do
  Begin
    n_Spalten:= Length(Matrix[Zeile]);
   
    For Spalte:= 0 To n_Spalten - 1 Do
    Begin
      Write(Matrix[Zeile, Spalte].ToString.PadLeft(Pad));
      Write(Leer);
    End;
    WriteLn;
  End;
  WriteLn('--------------------------');
  WriteLn;
End;{PrintMatrixX}
{----------------}

Procedure Make_3EckMatrix(VAR DreiEckMatrix: TMatrix;
                              n_Spalten_Max: Integer);
// Dynamische DreiEckMatrix dimensionieren

VAR
  Zeile : Integer;
  Spalten: Integer;

Begin
  SetLength(DreiEckMatrix, N_Spalten_Max, 0); // Zunächst NUR einen Vektor anlegen

  Spalten:= N_Spalten_Max;  

  For Zeile:= Low(DreiEckMatrix) To High(DreiEckMatrix) Do
  Begin
    SetLength(DreiEckMatrix[Zeile], Spalten);
    Dec(Spalten);
  End;
End;{Make_3EckMatrix}
{-------------------}

VAR
  n_Spalten_Max: Integer;
  DreiEckMatrix: TMatrix;
 
Begin
  ReportMemoryLeaksOnShutdown:= True;

  Try
    Try
      n_Spalten_Max:= 10;
      WriteLn('n_Spalten_Max = ', n_Spalten_Max);
     
      Make_3EckMatrix(DreiEckMatrix, n_Spalten_Max);
      PrintMatrixX(DreiEckMatrix, 'DreiEckMatrix');

      ReadLn;
     
    Finally
      // DreiEckMatrix:= NIL; // Nicht nötig? Wird anscheinend automatisch freigegeben?
    End;
  Except
    On E: Exception Do
      Writeln(E.ClassName, ': ', E.Message);
  End;
End.
Meine Frage:
Wieso meldet weder
Delphi-Quellcode:
ReportMemoryLeaksOnShutdown:= True;
noch madExcept einen Speicherleck, wenn ich die dynamische Struktur gar nicht freigebe?

Vorsichtshalber habe ich ein
Delphi-Quellcode:
 DreiEckMatrix:= NIL;
im Finally-Block hinzugefügt, frage ich mich jedoch, ob nicht eine Speicher-Freigabe analog zum Anlegen via
Delphi-Quellcode:
Make_3EckMatrix(..)
per For-Schliefe notwendig wäre.

Weiß jemand eine Antwort?
Danke im Voraus!

Viele Grüße
Andreas

Uwe Raabe 27. Mai 2022 17:08

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Dynamische Arrays werden bei Verlassen des Scopes automatisch freigegeben.

TurboMagic 27. Mai 2022 17:10

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Also wenn ich's richtig sehe ist da nirgends ein Create in deinem Code, oder?
Dann wird auch kein Objekt irgendwo erzeugt und damit gibt's auch kein Speicherleck weil du dann
nur einen dynamischen Array erzeugst und der wird ja automatisch verwaltet.

Andreas13 27. Mai 2022 17:22

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Ich habe es - noch zu Zeiten von Delphi 5 so gelernt - und dies seither auch stets so gehandhabt, daß jedes mit
Delphi-Quellcode:
SetLegth(My_Array, Len)
erzeugte dynamische Array am Ende mit
Delphi-Quellcode:
My_Array:= NIL;
freigegeben werden muß.
Von diesem (für mich neuen) Comfort habe ich bis jetzt nichts mitbekommen...:oops:
Danke!
Grüße, Andreas

dummzeuch 27. Mai 2022 17:45

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Zitat:

Zitat von Andreas13 (Beitrag 1506433)
Ich habe es - noch zu Zeiten von Delphi 5 so gelernt - und dies seither auch stets so gehandhabt, daß jedes mit
Delphi-Quellcode:
SetLegth(My_Array, Len)
erzeugte dynamische Array am Ende mit
Delphi-Quellcode:
My_Array:= NIL;
freigegeben werden muß.

Ich erinnere mich nicht, dass das bei Delphi 5 notwendig gewesen wäre. Das mag aber meinem schlechten Gedächtnis geschuldet sein. Ich könnte ja jetzt mein Notebook mit der Delphi 5 Installation rauskramen...

Andreas13 27. Mai 2022 19:39

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Hallo Thomas,
Du magst recht haben. Allerdings konnte ich nach einigem Suchen herausfinden, wo ich das gelernt habe: In einem von mir hochgeschätzten und vielbenutzen Buch:
Doberenz + Gewinnus: Borland Delphi 7: Grundlagen Profiwissen, 2003. S. 93/94.
Bis jetzt hat es meine Programme nicht gestört, wahrscheinlich war es aber, wie Ihr alle schreibt, überflüssig.
Man(n) lernt ja bekanntlich nie aus. :oops:
Danke Euch allen!

Viele Grüße
Andreas

TurboMagic 27. Mai 2022 20:25

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Naja, der Code für den Multimedia Timer dieser beiden Herren ist jedenfalls etwas fehlerhaft und nicht wie gezeigt lauffähig...

Soviel zur Schätzung ;-)
Aber ja, es gibt schlechtere Bücher...

himitsu 27. Mai 2022 21:46

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Managed Typen verwaltet Delphi automatisch, also Speicherfreigabe und deswegen auch immer eine autmatische Initialisierung der Variable mit 0 (nil).

Interfaces
Variants
dynamische Arrays
LongStrings (alle Strings außer ShortString, aber der ist ein statisches Array und somit auch automatisch weg)
und neuerdings auch Custom Managed Records (wenn man Initialize und Finalize implementiert hat)

TiGü 30. Mai 2022 08:24

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Bevor du das Rad neu erfindest, schau dir doch auch die Unit System.Math.Vectors an.
Vielleicht ist da was dabei, was du gebrauchen kannst.
Gibt es meines Wissens nach ab Delphi Seattle aufwärts.

https://docwiki.embarcadero.com/Libr...m.Math.Vectors

Redeemer 30. Mai 2022 09:32

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Zitat:

Zitat von Andreas13 (Beitrag 1506433)
Ich habe es - noch zu Zeiten von Delphi 5 so gelernt - und dies seither auch stets so gehandhabt, daß jedes mit
Delphi-Quellcode:
SetLegth(My_Array, Len)
erzeugte dynamische Array am Ende mit
Delphi-Quellcode:
My_Array:= NIL;
freigegeben werden muß.

Gilt nur für threadvar, oder? Bei threadvar muss man auch Strings leeren.

himitsu 30. Mai 2022 11:29

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Ja, ThreadVar ist ein Sonderfall, aber bei allem Anderen werden gemanagte Typen ordentlich behandelt.

Aufpassen muß man z.B. wenn man Speicher für Records, oder so, via GetMem/FreeMem und Co. holt/freigibt.
Aber New/Dispose beachten sowas.



ThreadVar:

In der Hilfe wird zwar Einiges gesagt, aber das auch nicht ganz Richtig und Vieles fehlt komplett (z.B. was man dort besser nur mit viel Vorsicht verwenden sollte, oder besser garnicht, also was man da am Ende selber Freigeben muß).
Außerdem wäre es nett, wenn hier der Compiler bereits eine Warnung für solche Typen werfen würde, denn er weiß ja welches ein gemanagter Typ ist, bzw. Pointer allgemein (wo er nicht weiß, ob es nur auf was Anderes zeigt, oder ob der Entwickler dort Selbsterstelltes reintun wird).

Bei Strings/Interfaces/Objekten/Variants/DynArrays/... würde z.B. gern ein Speicherleck entstechen, wenn der Programmierer es nicht freigibt, denn Delphi/Windows macht es nicht automatisch, beim Ende des Threads,
also wäre es besser sowas besser nicht zu verwenden.

Zitat:

Bei Zeigern und Funktionen ist diese Art der Deklaration nicht möglich. Typen, bei denen ein Schreibzugriff einen Kopiervorgang impliziert, wie lange Strings, können nicht als Thread-Variablen deklariert werden.
Das stimmt so nicht ganz -> Doch, kann man.

Die Referenzzählung ist thread-save, auch was den "Kopiervorgang" betrifft, denn erst wird referenzgezählt (beim Schreibzugriff auf Unique geändert) und dann in die "eine" eigene Referenz geschrieben.
Ganze Strings zuweisen geht ohne Probleme, was hängen könnt, wäre z.B. wenn man via PChar/Pointer drauf zugreift, bzw. einzelne Chars über den Arrayzugriff auslesen will (schreiben geht, bei LongStrings, aber nicht bei DynArrays).
Bei DynArrays gibt es leider kein Copy-on-Write, was das Ändern einzelner Felder etwas unpraktisch macht, wenn man das Array nicht vorher selber "unique" macht.
Strings mit Pointerzugriff könnte man vorher via Delphi-Referenz durchsuchenUniqueString explizit absichern, was aber beim Cast mit PChar meistens bereits automatisch gemacht wird.

Andreas13 30. Mai 2022 14:33

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Zitat:

Zitat von dummzeuch (Beitrag 1506435)
Zitat:

Zitat von Andreas13 (Beitrag 1506433)
Ich habe es - noch zu Zeiten von Delphi 5 so gelernt - und dies seither auch stets so gehandhabt, daß jedes mit
Delphi-Quellcode:
SetLegth(My_Array, Len)
erzeugte dynamische Array am Ende mit
Delphi-Quellcode:
My_Array:= NIL;
freigegeben werden muß.

Ich erinnere mich nicht, dass das bei Delphi 5 notwendig gewesen wäre...

Habe gerade in meiner lokalen Hilfe-Datei zu XE5 (Stand ca. 2013) folgenden Hinweis gefunden: ms-help://embarcadero.rs_xe5/rad/Strukturierte_Typen.html
Zitat:

Dynamische Array-Variablen sind implizit Zeiger und werden mit derselben Referenzzählung verwaltet wie lange Strings. Um ein dynamisches Array freizugeben, weisen Sie einer Variable, die das Array referenziert, den Wert nil zu, oder Sie übergeben die Variable an Finalize. Beide Methoden geben das Array unter der Voraussetzung frei, dass keine weiteren Referenzen darauf vorhanden sind. Dynamische Arrays werden immer freigegeben, sobald ihr Referenzzähler null ist. Dynamische Arrays der Länge 0 haben immer den Wert nil.
Leider wird nirgends aufgeführt, welche Typen "gemanagt" sind und somit automatisch freigegeben werden. :(
Grüße, Andreas

himitsu 30. Mai 2022 14:48

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Man kann alles an Finalize übergeben ... am Ende des Scopes (z.B. im END; von Funktionen wird Dieses aufgerufen, in einem implizitem Try-Finally, sobald gemanagte lokale Variablen vorhanden sind)

Was:
Zitat:

Strings/Interfaces/Objekten/Variants/DynArrays
zzgl. CustomManagedRecords

genauer LongStrings (alle Delphi-Strings, außer ShortString und WideString) sind wie aufgemotzte dynamische Arrays.
Der WideString ist sogar "eigentlich" eine gekapselte WinAPI für einen BSTR / OLE-String (siehe MSDN-Library durchsuchenSysAllocString).

dummzeuch 30. Mai 2022 18:12

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Zitat:

Zitat von Andreas13 (Beitrag 1506518)
Zitat:

Zitat von dummzeuch (Beitrag 1506435)
Zitat:

Zitat von Andreas13 (Beitrag 1506433)
Ich habe es - noch zu Zeiten von Delphi 5 so gelernt - und dies seither auch stets so gehandhabt, daß jedes mit
Delphi-Quellcode:
SetLegth(My_Array, Len)
erzeugte dynamische Array am Ende mit
Delphi-Quellcode:
My_Array:= NIL;
freigegeben werden muß.

Ich erinnere mich nicht, dass das bei Delphi 5 notwendig gewesen wäre...

Habe gerade in meiner lokalen Hilfe-Datei zu XE5 (Stand ca. 2013) folgenden Hinweis gefunden: ms-help://embarcadero.rs_xe5/rad/Strukturierte_Typen.html

Eben: Man kann ein dynamisches Array explizt freigeben aber man muss das nicht tun. Abgesehen davon ging es doch um Delphi 5 (released 1999, ), nicht Delphi XE5 (released 2013), oder nicht?

Andreas13 30. Mai 2022 19:47

AW: Warum wird eine dynamisch erzeugte Matrix scheinbar automatisch freigegeben?
 
Hi Thomas,
damit wollte ich nur sagen, daß die eingebaute Delphi-Hilfe selbst bei XE5 (Stand: 2013) immer noch nicht von einer automatischen Freigabe ("managed Type") spricht, sondern nur von Nil oder Finalize zur Freigabe des Speichers.
Was mich gewundert hat, war, daß wenn ich weder Nil noch Finalize benutze, das dynamische Array trotzdem freigegeben wird. :)
Grüße, Andreas


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