Autor Beitrag
perry5
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Mi 24.01.07 00:48 
Ok, ich habe also so ein dynamisches Array.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
type RColor = record
 Blue  : LongWord;
 Green : LongWord;
 Red   : LongWord;
 Alpha : LongWord;
end;

m_Picture : array of RColor;
SetLength(m_Picture, m_XSize*m_YSize);

So. Es funktioniert auch alles ganz wunderbar, aber was genau muss ich jetzt machen, um das freizugeben? Einfach gar nix, oder SetLength(m_Picture, 0), oder Finalize(m_Picture, Length(m_Picture)), oder halt Finalize(m_Picture) (also ohne die Länge anzugeben), oder noch was anderes?

Und was kann ich tun, wenn ich jetzt sagen wir 5 Objekte habe, die alle das selbe Objekt kennen, wie kann ich das am einfachsten dann freigeben? Im jeden Destruktor einfach den Destruktor dieses Objektes aufrufen, oder TObject.Free, oder was? Es wäre halt schön, wenn ich das nur im Destruktor erledigen könnte, da es mehrere solcher Fälle gibt, die ich dann alle verwalten müsste, was das ganze ja mehrmals komplizierter macht. Also, gibt es einen sicheren Weg, ein Objekt mehrmals freizugeben, so dass es keine fehelr gibt und das Objekt am Ende freigegeben ist?

Immerhin will ich doch, das jeder benutze Speicher wieder freigegeben wird, damit ich nicht über die schlechte Note, die mir mein Infolehrer sonst gibt, traurig bin.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 24.01.07 01:06 
Moin!

user profile iconperry5 hat folgendes geschrieben:
aber was genau muss ich jetzt machen, um das freizugeben?

Du kannst zum Beispiel m_Picture := NIL; nehmen oder auch Finalize(m_Picture); das dürfte egal sein. ;)

user profile iconperry5 hat folgendes geschrieben:
Einfach gar nix

Geht sogar auch, der Compiler gibt den Speicher AFAIK automatisch frei. ;)

user profile iconperry5 hat folgendes geschrieben:
Und was kann ich tun, wenn ich jetzt sagen wir 5 Objekte habe, die alle das selbe Objekt kennen, wie kann ich das am einfachsten dann freigeben?

Hm, andere Frage, anderer Thread! :mahn: ;) Aber da es mit "Speicher freigeben" zu tun hat... :zwinker:

user profile iconperry5 hat folgendes geschrieben:
Im jeden Destruktor einfach den Destruktor dieses Objektes aufrufen, oder TObject.Free, oder was?

Ein Objekt sollte immer einen Eigentümer haben, der sich um die "Besitzrechte" kümmern, also z.B. das Freigeben erledigen muss. Du kannst einer Referenz nicht ansehen, ob daran ein gültiges Objekt hängt. Deshalb könntest du den Objekten eine weitere Eigenschaft z.B. OwnsSubObject: Boolean; verpassen, die du nur in einem Objekt auf TRUE setzt. Und im Destruktor fragst du dann ab, ob das Objekt andere Objekte "besitzt" und gibst diese ggfs. frei. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
perry5 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Mi 24.01.07 01:28 
Joah, ich wollte auch fast n neuen Thread aufmachen, aber naja.
Also, wenn man ein Objekt nur einmal freigeben sollte, was passeirt wenn mans tortzdem einfach öfters macht?
ich meien es kommt ja keine Fehlermeldung.
Und das der Compiler automatisch alles freigibt, naja, ich weiß nciht. Mir kams so vor, jedenfalls stands im Taskmanager, das mein Programm immer mehr speicher reservierte, und dann kann ja eignetlihc nicht alles automatisch freigegeben worden sein, oder?
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 24.01.07 01:41 
Moin!

user profile iconperry5 hat folgendes geschrieben:
Also, wenn man ein Objekt nur einmal freigeben sollte, was passeirt wenn mans tortzdem einfach öfters macht?

Das hängt davon ab, wie du das machst. ;) Sollte aber z.B. eine fette AV liefern... :D

user profile iconperry5 hat folgendes geschrieben:
ich meien es kommt ja keine Fehlermeldung.

Was willst du denn nun, "sauber" programmieren oder "funktioniert-doch"-Ansatz... :gruebel: :? Man gibt ein Objekt nur einmal frei, Punkt. :mahn: ;)

user profile iconperry5 hat folgendes geschrieben:
Und das der Compiler automatisch alles freigibt, naja, ich weiß nciht. Mir kams so vor, jedenfalls stands im Taskmanager, das mein Programm immer mehr speicher reservierte, und dann kann ja eignetlihc nicht alles automatisch freigegeben worden sein, oder?

Woher soll ich wissen, was dein Programm macht, wenn du keinen Quelltext zeigst. ;) Abgesehen davon gilt die Aussage natürlich nur für z.B. lokale Variablen, also Dinge, deren Fokus der Compiler erfassen kann. Wenn du laufend gloable dynamische Objekte anlegst, wird da natürlich nix automatisch freigegeben. :|

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Mi 24.01.07 07:25 
Normalerweise fügt der Compiler automatisch Freigabecode in z.B. Prozeduren und Funktionen ein (genauer: nach jedem Block), wenn eine dynamische Variable keine Verwendung mehr hat. Folglich kann man z.B. einen lokal definierten string einfach stehen lassen, er wird automatisch entfernt. Gleiches gilt für dynamisch erstellte Arrays etc., aber man sollte sich dennoch möglichst saubere Konstrukte angewöhnen.

Bei Objekten immer
Object.Free oder FreeAndNil(Object) verwenden - letzteres stellt den Pointer auf NIL, so dass auch ein weiteres Free keine Probleme macht. Probleme kann es nämlich durchaus geben, wenn nicht auf NIL gesetzte Zeiger nochmal freigegeben werden.

Bei dynamischen Feldern
mit Setlength(Feld,0) zumindest den allokierten Speicher dann freigeben, wenn man ihn nicht mehr braucht (selbst wenn dann kurz danach der Compiler selbst nochmal 'aufräumt').
Aber Feld:=nil hat auch hier quasi denselben Effekt. Ist reine Geschmackssache.

_________________
Es gibt keine Probleme - nur Lösungen!
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 24.01.07 11:28 
user profile iconLogikmensch hat folgendes geschrieben:
Probleme kann es nämlich durchaus geben, wenn nicht auf NIL gesetzte Zeiger nochmal freigegeben werden.

Das stimmt nicht. Free überprüft vorher, ob der Zeigernil ist oder nicht. Deswegen soll man ja auch immer Free zum freigeben nutzen und nie Destroy, weil Destroy dies eben nicht tut und dann knallt es eben.

Zitat:
Bei dynamischen Feldern
mit Setlength(Feld,0) zumindest den allokierten Speicher dann freigeben, wenn man ihn nicht mehr braucht (selbst wenn dann kurz danach der Compiler selbst nochmal 'aufräumt').
Aber Feld:=nil hat auch hier quasi denselben Effekt. Ist reine Geschmackssache.

Das glaube ich nicht. Mit nil machst du nur die Variable "ungültig", der Speicher ist aber weiterhin belegt. Dynamische Arrays sollten mit Finalize freigegeben werden:
Zitat:
Finalize sollte nur in Situationen verwendet werden, in denen 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.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19312
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 24.01.07 11:35 
user profile iconLuckie hat folgendes geschrieben:
user profile iconLogikmensch hat folgendes geschrieben:
Probleme kann es nämlich durchaus geben, wenn nicht auf NIL gesetzte Zeiger nochmal freigegeben werden.

Das stimmt nicht. Free überprüft vorher, ob der Zeigernil ist oder nicht. Deswegen soll man ja auch immer Free zum freigeben nutzen und nie Destroy, weil Destroy dies eben nicht tut und dann knallt es eben.

Genau das hat er doch gesagt ;-). Das Problem ist doch, dass Free den Zeiger eben nicht unbedingt auf nil setzt. Und dann gibts Probleme bei einem erneuten Aufruf von Free.
Im Gegensatz zu FreeAndNil eben.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 24.01.07 11:44 
Moin!

user profile iconNarses hat folgendes geschrieben:
user profile iconperry5 hat folgendes geschrieben:
aber was genau muss ich jetzt machen, um das freizugeben?

Du kannst zum Beispiel m_Picture := NIL; nehmen oder auch Finalize(m_Picture); das dürfte egal sein.

user profile iconLuckie hat folgendes geschrieben:
Das glaube ich nicht. Mit nil machst du nur die Variable "ungültig", der Speicher ist aber weiterhin belegt. Dynamische Arrays sollten mit Finalize freigegeben werden:
Zitat:
Finalize sollte nur in Situationen verwendet werden, in denen 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.

Folglich ist meine Aussage falsch, Finalize() ist also die Wahl! ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 24.01.07 15:33 
user profile iconjaenicke hat folgendes geschrieben:
Das Problem ist doch, dass Free den Zeiger eben nicht unbedingt auf nil setzt. Und dann gibts Probleme bei einem erneuten Aufruf von Free.

Ein weiteres Problem ist, wenn man den Zeiger nicht auf nil setzt und man dann versuch mit Assigtned den Zeiger auf Gültigkeit zu prüfen.
perry5 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Mi 24.01.07 15:54 
OK, also erstmal das Problem mit den dynamischen Arrays:
ausblenden Delphi-Quelltext
1:
2:
var Name : array of Typ;
SetLength(Name, x);

Wir nehmen jetzt einfach mal an, dass Typ jeder normale Typ, und jedes Rekord sein kann, also, das Typ keine Klasse ist (weil dann ja Konstruktoren und Destruktoren aufgerufen werdne müssten, richitg?).
Einmal hab ich das als ObjektMember, d.h. das Array wird nur dann freigegeben, wenn der Destruktor aufgerufen wird, right?
Dann noch als lokale Variable, die würde dann ja freigegeben, wenn die Funktion/Procedure beendet wird, right?
So, wie schaffe ich es jetzt zuverlässig für alle Fälle gültig, in höchstens 2 Zeilen, das alles korrekt freigegeben wird, also quasi alles so wird, als wäre das array nie erzeugt worden?
Hierbei geht es wohlgemerkt darum, das nur EINER das array besitzt, es wird also nciht doppeltoder so freigegeben, und nach der freigabe garantiert nicht mehr benutzt (was ja passieren könnte, wenn das array, wie auch immer von mehreren Funktionen bzw. Objekten gleichzeitig benutzt werden würde).

Das mit den mehrfach benutzen Objekten werde ich glaube ich dann so lösen, dass diese entsprechenden Objekte einfach mehrmals vorhanden sind. d.h. jeder sein eigenes hat und dementsprechend freigibt.

Achja, um Objekte freizugeben: Ruft man den selber geschriebenen Destruktor auf, oder nimmt man Free() oder osnst irgendwas?
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Do 25.01.07 10:58 
Luckie hat geschrieben:
Zitat:
Das stimmt nicht. Free überprüft vorher, ob der Zeigernil ist oder nicht. Deswegen soll man ja auch immer Free zum freigeben nutzen und nie Destroy, weil Destroy dies eben nicht tut und dann knallt es eben.


Ja, Luckie, hast recht. Ich meinte doch die dynamischen Arrays und nicht Klassen. dyn. Arrays kannst Du sehr wohl mit Feld:=nil freigeben. Der entsprechende Finalize-Code wird dann auch ausgeführt. Aber ich muss Dir insoweit recht geben, dass die Anweisung an sich nicht schön (und verlässlich) ausschaut.

Zitat:
Das glaube ich nicht. Mit nil machst du nur die Variable "ungültig", der Speicher ist aber weiterhin belegt. Dynamische Arrays sollten mit Finalize freigegeben werden:


Nun, möglich das ich da tatsächlich falsch liege, aber die Erkenntnis habe ich vor Jahren hier aus diesem Forum gezogen. Da waren viele der Ansicht, dass eine Zuweisung an NIL eben jeden Finalize-Schritt impliziert ausführt. Vielleicht sollte ich es spaßeshalber mal im Debugging überprüfen...

Finalize sollte nur in Situationen verwendet werden, in denen 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.

Ich habe ja nichts dagegen, aber ich habe ehrlich gesagt bislang wenig Code gesehen, wo Finalize zur Freigabe von Arrays verwendet wird. Ich werde der Sache gerne nochmal nachgehen.

_________________
Es gibt keine Probleme - nur Lösungen!
perry5 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Do 25.01.07 14:29 
Allso schreibe ich jetzt einfach immer:
ausblenden Delphi-Quelltext
1:
array:=NIL;					

???
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 25.01.07 14:49 
Moin!

Bis zum Beweis, dass die Zuweisung von NIL den gleichen Effekt hat, wie die Übergabe an Finalize, würde ich definitiv Finalize() nehmen; ist auf jeden Fall die richtige Wahl, das andere wäre sowieso nur eine (eher unschöne) Alternative. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Heiko
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3169
Erhaltene Danke: 11



BeitragVerfasst: Do 25.01.07 16:26 
Ich habe mir gerade mal den ASM-Code angeguckt.
Im Vergleich hatte ich
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.FormCreate(Sender: TObject);
var
  a: array of integer;
begin
  SetLength(a, 5);
  Finalize(a);
end;


vs.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.FormCreate(Sender: TObject);
var
  a: array of integer;
begin
  SetLength(a, 5);
  a:=nil;
end;

Ergebnis: Finalize macht nach ein ganz paar Vergleiche bevor er DynArrayClear aufruft, während die nil-Variante es sofort macht. In dem Fall ist es also egal. Ich habe auf Anhieb auch keinen Fall gefunden, wo die Vergleiche davor etwas anderes ergeben (denn unter bestimmten Fällen ruft er eine Rekusion von FinalizeArray auf, den ich aber nie getroffen habe).

Letzteres habe mit einem array of array of WideString und einem array of WideString probiert. Es ist also scheinbar egal, was man aufruft, wobei die nil-Variante auf dem CPU schneller ist. Wenn einer eine Variante findet, wo ein cmp-Befehl anders anschläft, würde es mich mal glatt interessieren, denn selbst bei einem Array von einer Klasse (habs mit TColor getestet, wobei ichs Create nicht vergessen habe ;) ), spüringen die nicht an.

Grüße Heiko
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Fr 26.01.07 10:19 
Auch auf die Gefahr hin, dass ich von Christian geprügelt werde: Dynamische Arrays werden ganz ähnlich verwaltet (zumindest was das Speichermanagement angeht) wie lange Strings. Ein überaus einfaches aber doch sinnvolles Verfahren speichert zu dem reservierten Speicherbereich einen Referenzzähler. Erst wenn dieser auf 0 kommt, wird der Speicher freigegeben. So ist z.B. das Äquivalent von <dynamisches Array>:=nil bei Strings <String>:=''. Auch dabei wird der reservierte Speicher des Strings (falls kein anderer Zeiger auf diesen Speicher zeigt) freigegeben und der String-Zeiger auf NIL gesetzt. Das nur nebenbei.

Fazit: Bei dynamischen Arrays ist Finalize sicherlich die optisch schönste Variante. Dennoch gebe ich in Prozeduren/Funktionen dynamisch definierte Arrays (und strings) nicht frei, weder mit NIL-Zuweisung noch über finalize. Allerhöchstens setze ich dynamische Arrays mit Setlength auf 0. Aber auch das könnte ich mir eigentlich sparen. Aber man kann über geschmackliche Dinge bekanntlich ewig streiten, ohne dass was dabei rauskommt. ;-)

_________________
Es gibt keine Probleme - nur Lösungen!
perry5 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Fr 26.01.07 15:43 
user profile iconLogikmensch hat folgendes geschrieben:

Fazit: Allerhöchstens setze ich dynamische Arrays mit Setlength auf 0. Aber auch das könnte ich mir eigentlich sparen.

Ja was den jetzt? :-D
Muss ich was machen oder nicht?Meinste damit, dass die nicht freigegeben werden, dass man nach dem :=0 quasi wieder SetLength() aufrufen könnte?
Und wenn man sich das sparen könnte: Wird dann jetzt der speicher automatisch freigegeben? Ich habe halt das deutliche Gefühl (TaskManager) das ich jede menge Speicher benutze, der nie freigegeben wird.
Logikmensch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 390

Win XP
Delphi 2007 Prof., XE2, XE5
BeitragVerfasst: Fr 26.01.07 16:06 
Hey perry5, ich wollte Dich jetzt nicht verunsichern. Mache es so, wie Luckie empfiehlt - gib die Arrays mit Finalize frei und Objekte mit Free oder FreeAndNil. Ob der Delphi-Rahmencode dann das ganze nochmal freigibt, kann Dir praktisch egal sein.
Wenn Du wirklich den Verdacht hast, dass Speicher nicht freigegeben wird, solltest Du mal einen Speichermonitor schreiben, also quasi in regelmäßigen Abständen (TTimer) den belegten Speicher prüfen und Dir anzeigen oder auflisten lassen (TMemo). Was aber dynamische Arrays, die innerhalb von Prozeduren oder Funktionen deklariert (!) und allokiert werden angeht, kann ich Dich beruhigen - die werden von Delphi auf alle Fälle nach Verlassen der Proc/Func automatisch freigegeben.

_________________
Es gibt keine Probleme - nur Lösungen!
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Fr 26.01.07 16:26 
Dynamische Arrays sind sowieso in der OOP obsolete und sollten durch Containerklassen ersetzt werden, die Objekte aufnehmen und verwalten.
perry5 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 102



BeitragVerfasst: Fr 26.01.07 17:50 
Gutes Stichwort ;-)

Ich enutze auch eine TList, die ja scheinbar im inneren einfach nur ein dynamsiches Array verwaltet.
Die würde dann automatisch freigegeben, wenn der TList-Desktrutor aufgerufen wird?

Und wenn das ein Array aus Objekt Zeiger ist, muss ich das vor dem zerstören einmal komplett durchgehen und jedes Objekt löschen?
Und muss ich das bei normalen dynmaischen Arrays auch machen?
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 27.01.07 00:22 
Bei Objekten ja. Da kannst du aber auch eine TObjectList nehmen, die verwaltet die Objekte selber.