![]() |
Speicherfreigabe mit Dispose
Ich habe ein Verständnisproblem bei der Speicherfreigabe mit Dispose.
Ich habe mir einen Ringspeicher zur Aufnahme von Messdaten auf Basis eines TList definiert. Vor dem Hinzufügen eines neuen Elements wird zunächst geprüft, ob die Maximalgröße des Buffers erreicht ist und gegebenenfalls das älteste Element (also das erste in der Liste gelöscht). Im Code sieht das etwa so aus:
Code:
Hierbei wird aber durch Dispose der Speicherplatz des Elements Buffer.Items[0] nicht freigegeben!
Buffer: TList;
procedure AddRecord(ARecord: TDataRecord); var P: PDataRecord; begin New(P); P^.Values := Copy(ARecord.Values); if Buffer.Count = fMaxBufSize then begin Dispose(Buffer.Items[0]); Buffer.Delete(0); end; Buffer.Add(P); end; Erst wenn ich den Code wie folgt umschreibe, funktioniert es:
Code:
Kann mir jemand den Unterschied erklären?
procedure AddRecord(ARecord: TDataRecord);
var P, P2: PDataRecord; begin New(P); P^.Values := Copy(ARecord.Values); if Buffer.Count = fMaxBufSize then begin P2 := Buffer.Items[0]; Dispose(P2); Buffer.Delete(0); end; Buffer.Add(P); end; Das Problem führte bei mir nach einigen Wochen Programmlaufzeit zu einem Speicherfehler und war daher sehr schwer zu lokalisieren. |
AW: Speicherfreigabe mit Dispose
TList.Items[] liefert einen untypisierten Zeiger (Datentyp Pointer). Dispose weiß somit nicht, dass sich hinter dem Zeiger ein PDataRecord befindet und wird zu einem einfachen "FreeMem" umfunktioniert, womit alle "managed" Datentypen innerhalb des Records nicht richtig aufgeräumt werden.
Beim zweiten Beispiel weiß Dispose nun vom passenden Typ und kann den Inhalt des Records (Strings, Dynamische Arrays, Interfaces) korrekt aufräumen. |
AW: Speicherfreigabe mit Dispose
Wäre es nicht besser, wenn Dispose hier eine Warnung ausgeben würde, wenn es einen untypisierten Pointer bekommt?
|
AW: Speicherfreigabe mit Dispose
Zitat:
|
AW: Speicherfreigabe mit Dispose
Danke für die Antworten.
Die Erklärung von jbg ist einleuchtend, hier heißt es also aufzupassen, was für einen Zeiger man übergibt. |
AW: Speicherfreigabe mit Dispose
Zitat:
|
AW: Speicherfreigabe mit Dispose
Zitat:
In diesem konkreten Falle allerdings durchaus. Dieser "Ringspeicher" ist nämlich alles andere als ein tatsächlicher Ringspeicher und
Delphi-Quellcode:
zu verwenden ist von der Performance her unter Umständen ziemlich übel. Das
TList
Delphi-Quellcode:
kostet hier nämlich sehr viel Zeit.
Delete(IrgendwasMittendrin)
Alternative wäre es ein
Delphi-Quellcode:
oder ggfls.
TArray<T>
Delphi-Quellcode:
zu verwenden und sich dazu den Start- und den End-Index zu merken. Add/Remove aus dem Buffer beschränkt sich dann auf ein einfaches Einfügen der Daten mit abschließendem
array[n..m] of T
Delphi-Quellcode:
bzw.
Inc()
Delphi-Quellcode:
der entsprechenden Indexvariable. Dynamische Speicherreservierungen hättest du dann zur Laufzeit auch komplett keine mehr.
Dec()
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:04 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 by Thomas Breitkreuz