Autor |
Beitrag |
Bergmann89
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Fr 11.09.09 00:49
HI,
ich habe folgenden Code:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure CommaTextToSingleList(CommaText: String; var List: TList); var Pos1: Integer; var value: PSingle; begin Pos1 := Pos(';',CommaText); while Pos1 <> 0 do begin new(value); value^ := StrToFloat(Copy(CommaText,0,Pos1-1)); List.Add(value); CommaText := copy(CommaText, Pos1+1, Length(CommaText)); Pos1 := Pos(';',CommaText); end; end; |
Muss ich den Speicher den die Items benutzen vorher selber mit Dispose freigeben, wenn ich ein Item aus der Liste mit List.del(index) lösche, oder die komplette Liste mit List.clear leere, oder macht das die Liste selbst?
Wenn ich es selbst machen muss, funktioniert das auch mit Records?
MfG & Thx Bergmann.
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
Tryer
      
Beiträge: 226
Erhaltene Danke: 7
|
Verfasst: Fr 11.09.09 05:17
Ja, den Speicher musst Du selber freigeben. Die Items stehen alle in einem "Array of Pointer" und die Liste kümmert sich nur um dieses Array, nicht aber um die Ziele der Zeiger.
Bei Werten vom Typ Single kannst Du Dir das aber auch sparen, da der Wert mit 4 Byte genauso gross ist wie der Zeiger darauf. Wenn Du es so machst (geht dann nicht für Records) brauchst Du nichts freizugeben (und sparst 50% Speicherplatz).
Delphi-Quelltext 1: 2: 3: 4:
| var Value: single; ... List.Add(Pointer(Value)); Value := Single(List.Items[0]); |
MfG,
Dirk
|
|
jaenicke
      
Beiträge: 19312
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 11.09.09 06:49
|
|
Bergmann89 
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Fr 11.09.09 15:02
Hey,
@Tryer: aber wenn ich mehrere Sachen in die Liste schreiben will und immer List.add(Pointer(Value)) nehm, dann zeigen doch alle Einträge der Liste auf Value und jeder Eintrag hat am Ende den selben Wert, oder? Und mir wurde vor paar Tagen hier im Forum auch gesagt, dass ich das new auf alle Fälle brauch.
Das freigeben vom Record mach ich mit FreeMem, un dann noch den Zeiger auf das record mit Dispose, oder?
@jaenicke: Hast Recht, hab ich grad geändert. Aber wäre es denn so schlimm, wenn das var stehen geblieben wäre?
MfG Bergmann
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
Tryer
      
Beiträge: 226
Erhaltene Danke: 7
|
Verfasst: Fr 11.09.09 15:21
Nein, es werden nicht alle Pointer auf Value zeigen..
Alle Pointer werden ungültig sein.
Erklärungsversuch:
Das Konstrukt "Pointer(Value)" entspricht nicht "@Value". Es ist kein Zeiger auf Value, sondern die Interpretation des Single-Wertes als Pointer. Im Speicher sind die Strukturen "Pointer" und "Single" gleich gross, darum geht das.
In dem Array wo normalerweise "echte" Pointer stehen, wird einfach der "falsche" Pointer "Value" eingetragen, deer ja gar kein Pointer sondern eine Gleitkommazahl ist.
Der Wert steht jetzt nicht an einer Adresse welche im Array steht, sondern direkt im Array.
New() brauchst Du nur wenn echte Pointer Verwendung finden.
[EDIT]
Zum Freigeben sollte ein Dispose() reichen, FreeMem brauchst Du eigentlich nur nach "GetMem". Wie ist der Record denn aufgebaut ?
[/EDIT]
MfG,
Dirk
Zuletzt bearbeitet von Tryer am Fr 11.09.09 15:38, insgesamt 1-mal bearbeitet
|
|
Bergmann89 
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Fr 11.09.09 15:33
Achso alles klar. Hat klick gemacht ^^
un wie is das jetzt mit den Records?
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
Tryer
      
Beiträge: 226
Erhaltene Danke: 7
|
Verfasst: Fr 11.09.09 15:43
Zitat: | [EDIT]
Zum Freigeben sollte ein Dispose() reichen, FreeMem brauchst Du eigentlich nur nach "GetMem". Wie ist der Record denn aufgebaut ?
[/EDIT] |
Sorry, hab etwas spät editiert.
MfG,
Dirk
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Fr 11.09.09 16:54
Aber um mal generell das Freigeben von Pointern in einer TList zu klären, hier ein Codeschnipsel von mir
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| procedure __Free_ImageListInfo(pData : PImageListInfo); begin While pData^.FpData.Count > 0 Do begin Dispose(PImageInfo(pData^.FpData.Items[0])); pData^.FpData.Delete(0); end; Dispose(pData); end;
begin ... While FpImageLists.Count > 0 Do begin __Free_ImageListInfo(PImageListInfo(FpImageLists.Items[0])); FpImageLists.Delete(0); end; FpImageLists.Free; ... end; |
Zur Erklärung : Wenn Du Einträge aus der TList löscht, verringert sich die Anzahl, also Count. Deswegen entweder vom höchsten Element ruterzählen zu 0 oder einfach immer das Element 0 löschen.
Im Bsp. Habe ich eine TList, die Zeiger auf Records enthält, diese records wiederrum beinhalten selbst je eine TList.
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
Tryer
      
Beiträge: 226
Erhaltene Danke: 7
|
Verfasst: Fr 11.09.09 17:39
Autsch, bitte nicht so!
Jedes Delete(0) sorgt dafür das der gesamte Listenteil dahinter um 4 Bytes nach vorne verschoben wird, das ist total überflüssig wenn man wie hier alle Einträge löschen will.
Delete macht nur dann Sinn wenn einzelne Einträge zu löschen sind.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| procedure __Free_ImageListInfo(pData : PImageListInfo); var i: Integer; begin for i := 0 to Pred(pData^.FpData.Count) do Dispose(PImageInfo(pData^.FpData.Items[i])); pData^.FpData.Free; end;
var p: PImageListInfo; i: Integer; begin ... for i := 0 to Pred(FpImageLists.Count) do begin p := FpImageLists.Items[i]; __Free_ImageListInfo(p); Dispose(p); end; FpImageLists.Free; ... end; |
MfG,
Dirk
|
|
Bergmann89 
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Fr 11.09.09 18:22
Hey,
mein record sieht so aus:
Delphi-Quelltext 1: 2: 3: 4:
| THighScoreItem = record Name: String; Score: Cardinal; end; |
also wirklich bloß was ganz einfaches.
Delphi-Hilfe hat folgendes geschrieben: | In Delphi erzeugt New eine neue dynamische Variable und gibt einen Zeiger auf den ihr zugewiesenen Speicher zurück. P ist eine Variable eines beliebigen Zeigertyps. Die Größe des reservierten Speicherblocks entspricht der Größe des Datentyps, auf den P zeigt. Auf die neue Variable kann mit P^ Bezug genommen werden. Ist nicht genug Speicher für die dynamische Variable verfügbar, wird eine EOutOfMemory-Exception ausgelöst.
Wenn eine mit New erzeugte dynamische Variable nicht mehr benötigt wird, sollte sie mit der Standardprozedur Dispose wieder freigegeben werden. |
Und demnach sollte ja ein normales Dispose reichen, also brauch ich kein FreeMem...
MfG Bergmann
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
HelgeLange
      
Beiträge: 735
Erhaltene Danke: 6
Windows 7
Delphi7 - Delphi XE
|
Verfasst: Sa 12.09.09 00:51
_________________ "Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
|
|
Tryer
      
Beiträge: 226
Erhaltene Danke: 7
|
Verfasst: Sa 12.09.09 07:41
Bergmann89 hat folgendes geschrieben : | Delphi-Quelltext 1: 2: 3: 4:
| THighScoreItem = record Name: String; Score: Cardinal; end; |
also wirklich bloß was ganz einfaches. |
Naja, nicht ganz so einfach.
Dein Record enthält einen "langen String", und der ist etwas schwierig zu behandeln da er genau wie jedes andere dynamisches Array ein Zeiger auf die Stelle ist an welcher die Daten sowie eine Längenangabe und ein Referenzzähler stehen.
Entweder setzt man den String auf '', oder man benutzt die Prozedur Finalize() welche das gleiche macht aber halt allgemeingültig ist und mit allen Datenstrukturen klar kommt.
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| PHighScoreItem(Item[i])^.Name := ''; Finalize(PHighScoreItem(Item[i])^); Dispose(PHighScoreItem(Items[i])); |
Wichtig (zumindest nach meinem Verständnis) ist das die an Finalize übergebene Struktur oder der an Dispose übergebene Zeiger richtig typisiert sind. Nur so kann die Funktion wissen was alles zu tun ist um den Speicher freizugeben. Da lasse ich mich aber gerne eines besseren belehren. Die OH zum Thema Finalize ist leider etwas schwammig geschrieben, ich halte mich da an die Resultate die mir Memproof liefert.
Im Normalfall wird ein Finalize()-Aufruf sich nie störend auswirken, da er bei Nichtgebrauch einfach wegoptimiert wird. Ein recht einfaches Test ob Finalize() benötigt wird ist also einen Breakpoint auf den Aufruf zu setzen und zu schauen ob dieser aktiv bleibt.
MfG,
Dirk
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Sa 12.09.09 08:41
@Tryer: Is ja ganz nett, was Du da erzählst, aber total überflüssig. Delphi erledigt das Alles für Dich.
Ein einfaches
Delphi-Quelltext
reicht vollkommen.
_________________ Na denn, dann. Bis dann, denn.
|
|
Tryer
      
Beiträge: 226
Erhaltene Danke: 7
|
Verfasst: Sa 12.09.09 08:52
Ist es dann ein Fehler von Memproof wenn mir dieses erzählt das bei durchgeführtem Dispose noch ein Finalize fehlen würde um den Speicher freizugeben?
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Sa 12.09.09 09:09
Weiss nicht, habe eben mit FastMM4 geprüft und da war nix... Ich habe es so gemacht:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| Type TRecord = Record s : String; x : Integer; End; PRecord = ^TRecord;
Var P : PRecord;
Begin New(P); P^.S := 'Some String'; Dispose(P); End. |
Bisher habe ich FastMM immer vertraut... Was sagt MemProof denn dazu?
Dispose ruft übrigens intern Finalize auf (hab ich mir schon gedacht). Vielleicht hast Du eine ältere Delphi-Version?
_________________ Na denn, dann. Bis dann, denn.
|
|
Tryer
      
Beiträge: 226
Erhaltene Danke: 7
|
Verfasst: Sa 12.09.09 10:35
Du hast recht, und mir ist wieder was klarer geworden.
Nur wenn man einen Record mit vielen Strings hat (also keinen Zeiger auf den Record sondern MyRec: TMyRecord, dann kann man statt einzeln für alle Strings SetLength(0) bzw :='' aufzurufen auch Finalize() verwenden.
Memproof meckert hier, und da zeigt sich das es halt wichtig ist das der Zeiger typisiert ist:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| Type TRecord = Record s : String; x : Integer; End; PRecord = ^TRecord;
Var P : PRecord;
Begin New(P); P^.S := 'Some String'; Dispose(Pointer(P)); End. |
Dispose gibt hier nur den Zeiger selber frei, aber kann halt garnicht wissen das da noch ein String hinterlegt ist. Das heißt für das Dispose von TList - Elementen das immer mit "Typisierung" Dispose(PMyRecord(Items[i])); gearbeitet werden muss.
MfG,
Dirk
|
|
Bergmann89 
      
Beiträge: 1742
Erhaltene Danke: 72
Win7 x64, Ubuntu 11.10
Delphi 7 Personal, Lazarus/FPC 2.2.4, C, C++, C# (Visual Studio 2010), PHP, Java (Netbeans, Eclipse)
|
Verfasst: Sa 12.09.09 12:14
OK,
dann sind ja alle Fragen beantwortet. Memproof und FastMM4 scheinen ja zeimlich nützliche Tools zu sein, das werd ich mir gleich mal näher ansehen...
MfG Bergmann
_________________ Ich weiß nicht viel, lern aber dafür umso schneller^^
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Sa 12.09.09 12:17
_________________ Na denn, dann. Bis dann, denn.
|
|
|