Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Record zurücksetzen (löschen) (https://www.delphipraxis.net/120638-record-zuruecksetzen-loeschen.html)

Hawkeye219 14. Sep 2008 14:58

Re: Record zurücksetzen (löschen)
 
Hallo,
Zitat:

Zitat von Neutral General
Damit dürften wohl alle Zweifel und Unklarheiten aus der Welt geschafft sein :)

Gab es noch welche? klick

Gruß Hawkeye

Neutral General 14. Sep 2008 15:03

Re: Record zurücksetzen (löschen)
 
ups :oops:

Hab aber nicht abgeschrieben, ehrlich :oops:

Hansa 14. Sep 2008 15:09

Re: Record zurücksetzen (löschen)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Bei verschachtelten Records läuft das genauso.

Delphi-Quellcode:
    MyRecord : record
      nr : Integer;
      name : string [10];
      MyRecord2 : record
        nr : Integer;
        name : string [10];
      end;
    end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyRecord.nr := 1;
  MyRecord.name := 'XYZ';
  MyRecord.MyRecord2.nr := 2;
  MyRecord.MyRecord2.name := 'XYZ2';
  memo2.Lines.Add(IntToStr(MyRecord.nr));
  memo2.Lines.Add('*'+MyRecord.name+'*');
  memo2.Lines.Add('');
  FillChar (MyRecord,SizeOf (MyRecord),0);
  memo2.Lines.Add(IntToStr(MyRecord.nr));
  memo2.Lines.Add('*'+MyRecord.name+'*');
  memo2.Lines.Add(IntToStr(MyRecord.MyRecord2.nr));
  memo2.Lines.Add('*'+MyRecord.MyRecord2.name+'*');
end;
Ergebnis : Anhang. In diesem Beispiel ist auch das Finalize völlig überflüssig.

SubData 14. Sep 2008 15:15

Re: Record zurücksetzen (löschen)
 
Hatten wir nicht gerade, dass bei globalen Variablen mit der Methode ein MemoryLeak auftritt ?!

Neutral General 14. Sep 2008 15:26

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Hansa
Bei verschachtelten Records läuft das genauso.

Delphi-Quellcode:
    MyRecord : record
      nr : Integer;
      name : string [10];
      MyRecord2 : record
        nr : Integer;
        name : string [10];
      end;
    end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyRecord.nr := 1;
  MyRecord.name := 'XYZ';
  MyRecord.MyRecord2.nr := 2;
  MyRecord.MyRecord2.name := 'XYZ2';
  memo2.Lines.Add(IntToStr(MyRecord.nr));
  memo2.Lines.Add('*'+MyRecord.name+'*');
  memo2.Lines.Add('');
  FillChar (MyRecord,SizeOf (MyRecord),0);
  memo2.Lines.Add(IntToStr(MyRecord.nr));
  memo2.Lines.Add('*'+MyRecord.name+'*');
  memo2.Lines.Add(IntToStr(MyRecord.MyRecord2.nr));
  memo2.Lines.Add('*'+MyRecord.MyRecord2.name+'*');
end;
Ergebnis : Anhang. In diesem Beispiel ist auch das Finalize völlig überflüssig.

Zitat:

Zitat von SubData
Hatten wir nicht gerade, dass bei globalen Variablen mit der Methode ein MemoryLeak auftritt ?!

Dieses Beispiel ist in diesem Thread hier total fehl am Platz. Dadurch, dass Hansa jetzt in seinem Record Shortstrings benutzt hat, gibts das Problem natürlich nicht. ShortStrings sind eben keine Pointer. Von daher ist ein Finalize tatsächlich nicht nötig. Was Hansa jetzt damit sagen/verdeutlichen will, weiß ich allerdings nicht. Mir scheint, als hätte er nicht verstanden, worum es hier in dieser Diskussion geht. :roll:

Hawkeye219 14. Sep 2008 15:32

Re: Record zurücksetzen (löschen)
 
Hallo,

noch einmal zur Klarstellung:

Bei referenzgezählten Daten (dynamische Strings und Arrays, Interfaces) sollte ein Aufruf von Finalize vorgeschaltet werden, damit die internen Verwaltungsinformationen aufgeräumt werden können. Der Compiler erzeugt dabei einen Aufuf der zugehörigen RTL-Routine, die selbst feststellen kann, welche Felder des Records finalisiert werden müssen. Dies sollte mit beliebig geschachtelten Datentypen funktionieren. "Einfache" Zeiger werden von Finalize nicht zerstört.

Bei Referenzen auf Speicherbereiche oder Objekte ist der Programmierer selbst für die Freigabe der referenzierten Objekte verantwortlich. Hierzu wird die komplementäre Routine (GetMem/FreeMem, Create/Free,...) aufgerufen, um den Speicher wieder freizugeben.

Einfache Datentypen (Ordinaltypen, Fließkommatypen, kurze Strings(!),...) benötigen keine Aufräumarbeiten.

Ein Aufruf von FillChar darf erst erfolgen, nachdem die Verwaltungsdaten ordnungsgemäß aufgeräumt wurden. Beachtet man dies nicht, entstehen Memory Leaks.

Gruß Hawkeye

Hansa 14. Sep 2008 15:39

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Neutral General
..als hätte er nicht verstanden, worum es hier in dieser Diskussion geht. :roll:

Es steht doch in #1, dass es hierum geht :

Delphi-Quellcode:
type
  TMyRecord = record
    Test_1:          string;
    Test_2:          string;
    Test_3:          string;
    Integer_1:       integer;
    Integer_2:       integer;
  end;

...

MyRecord: TMyRecord;
Und das Ding soll leergemacht werden. Wozu dann soviel Klimbim machen ? Von der Compiler-Direktive $H+ ist nichts zu sehen. Insofern ist das finalize überflüssig und wird sogar vom Linker entfernt.

DeddyH 14. Sep 2008 15:43

Re: Record zurücksetzen (löschen)
 
String ist nicht gleich String[10], das ist der Unterschied.

Christian Seehase 14. Sep 2008 18:35

Re: Record zurücksetzen (löschen)
 
Moin Hansa,

Zitat:

Zitat von Hansa
Von der Compiler-Direktive $H+ ist nichts zu sehen.

wozu auch, schliesslich stellt man dies, üblicher Weise, in den Projektoptionen ein.
Ausserdem sind Huge-Strings auch die Standardeinstellung.
Hast Du es bei Dir umgestellt? ;-)

Hansa 14. Sep 2008 18:49

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Christian Seehase
Ausserdem sind Huge-Strings auch die Standardeinstellung.
Hast Du es bei Dir umgestellt? ;-)

Ne, nichts umgestellt. Warum auch ? Die Screenshots wurden produziert mit Projektoptionen-Checkbox "Huge-Strings" angehakt. Mache ich aus dem string [10] nur string, dann gehts genauso. @DeddyH

FAlter 14. Sep 2008 18:52

Re: Record zurücksetzen (löschen)
 
Hi,

Zitat:

Zitat von Hansa
Zitat:

Zitat von Christian Seehase
Ausserdem sind Huge-Strings auch die Standardeinstellung.
Hast Du es bei Dir umgestellt? ;-)

Ne, nichts umgestellt. Warum auch ? Die Screenshots wurden produziert mit Projektoptionen-Checkbox "Huge-Strings" angehakt. Mache ich aus dem string [10] nur string, dann gehts genauso. @DeddyH

Vom Effekt her scheint es gleich zu sein, allerdings wird der Speicher nicht freigegeben, den die Strings belegen, sondern nur der Zeiger auf nil gesetzt (was bei Delphi Leerstring bedeutet).

Mfg
FAlter

Neutral General 14. Sep 2008 22:41

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Hansa
Ne, nichts umgestellt. Warum auch ? Die Screenshots wurden produziert mit Projektoptionen-Checkbox "Huge-Strings" angehakt. Mache ich aus dem string [10] nur string, dann gehts genauso. @DeddyH

Ich würde mal sagen: Damit wäre

Zitat:

Zitat von Neutral General
Mir scheint, als hätte er nicht verstanden, worum es hier in dieser Diskussion geht. :roll:

bewiesen :P

Natürlich wird der String auch ohne Finalize zu einem Leerstring. Allerdings hinterlässt du ein MemoryLeak.

Du machst quasi folgendes:

Delphi-Quellcode:
var pc: PChar;
begin
  GetMem(pc,6);
  // mit PChar arbeiten
  pc := nil; // = FillChar(String,SizeOf(String),0);
end;
Ich denke du siehst, dass obiger Code ein MemoryLeak verursacht. Richtig wäre es so:

Delphi-Quellcode:
var pc: PChar;
begin
  GetMem(pc,6);
  // mit PChar arbeiten
  FreeMem(pc); // Finalize(RecordmitString);
  pc := nil; // = FillChar(RecordmitString,SizeOf(TRecordmitString),0);
end;
Ich hoffe, du hast jetzt verstanden worum es geht. Im Endeffekt ist pc immer nil. Das Ergebnis ist scheinbar das Gleiche.

Luckie 14. Sep 2008 22:57

Re: Record zurücksetzen (löschen)
 
Hm. :gruebel:

also Records sind ja sowieso nicht mehr ganz OOP konform. Gerad ein so einen Fall bieten sich klassen an, da Klassen Daten und Methoden die Daten zu manipulieren kapseln. Da würde ich dann eine Methode Init schreiben, die die Attribute auf einen definierten Wert setzt.

Was passiert eigentlich mit String Attributen, wenn man des Objekt auf nil setzt?

Neutral General 14. Sep 2008 23:03

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Luckie
Was passiert eigentlich mit String Attributen, wenn man des Objekt auf nil setzt?

Der String liegt weiterhin im Speicher rum und wird nicht freigegeben. (MemoryLeak)

Luckie 14. Sep 2008 23:12

Re: Record zurücksetzen (löschen)
 
Das ist ja Müll.

Neutral General 14. Sep 2008 23:15

Re: Record zurücksetzen (löschen)
 
Was hast du denn erwartet/gehofft? :gruebel:

Luckie 14. Sep 2008 23:25

Re: Record zurücksetzen (löschen)
 
Dass der MemoryManager erkennt, dass es sich um Strings handelt und den Speicher entsprechend freigibt.

SubData 15. Sep 2008 07:10

Re: Record zurücksetzen (löschen)
 
So... Und ich hab da auch mal was nettes:

Folgendes Konstrukt:
Delphi-Quellcode:
type
  TThreadVars = record
    sServerHost : String;
    sRemoteIP  : String;
    sPHPSession : String;
    sVar1       : String;
    sVar2       : String;
    sVar3       : String;
    sVar4       : String;
    sVar5       : String;
    dVar1       : TDateTime;
    iVar1       : Int64;
    (* --- Request Infos --- *)
    pThread    : ^TIdContext;
    pRequest   : ^TIdHTTPRequestInfo;
    pResponse  : ^TIdHTTPResponseInfo;  
  end;

threadvar
  tv             : TThreadVars;
Am Anfang des Threads werden alle Felder gefüllt bzw. irgendwann im laufenden Thread.

Am Ende des Threads wird folgendes aufgerufen:

Delphi-Quellcode:
    Finalize(tv);
    FillChar(tv, SizeOf(tv), 0);
Und was passiert?

Richtig, ich hab ein Memory Leak.
Allerdings nur in den ersten 3 String Variablen.
Wenn ich diese per Hand auf zurücksetze ( var := ''; ) dann ist das Memory Leak weg...

jfheins 15. Sep 2008 08:49

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Luckie
Was passiert eigentlich mit String Attributen, wenn man des Objekt auf nil setzt?

Zitat:

Speicherleck ....... Ist ja Müll ...... Was hast du denn erwartet?
Zitat:

Zitat von Luckie
Dass der MemoryManager erkennt, dass es sich um Strings handelt und den Speicher entsprechend freigibt.

Wir sind heir doch nicht in .NET (oder Java) ;)

Da reicht ein nil setzen volkomen aus, und der Memorymanager(/GC) kümmert sich um den Rest ;)

Zum Thema: Eine Klasse wäre natürlich praktischer. Dann kannst du auch direkt die Klasse Thread-Safe implementieren und alles sollte klappen :stupid:

Guido Eisenbeis 16. Sep 2008 18:36

Re: Record zurücksetzen (löschen)
 
@All

OK, ... ich ... schreibe ... jetzt ... mal ... sehr ... langsam und lasse mir Zeit, bevor ich diese Posting losschicke. Ich will mich eigentlich schon die ganze Zeit bedanken für die rege Beteiligung und die wirklich guten Infos. Aber jedes Mal wenn ich ansetze, um dies zu schreiben kommen in der Zwischenzeit wieder neue Beiträge. ;-) Ihr seid richtig flott! Ich bin erfreut und beeindruckt, was hier eine rege Diskussion entstanden ist.

Ich habe an einem bestimmten Punkt gedacht, dass die FillChar-Möglichkeit eine Lösung für das Thema meines Threads ist. Dann kamen neue Infos und ich begann über die Speicherlecks zu grübeln. Dann war wieder alles klar, und nach einigen weiteren Post gings von vorne los. Ich träume schon von Speicherlecks! :cyclops:

Nun habe ich mich entschieden, dass die FillChar-Lösung die richtige für mein Problem ist und werde sie verwenden. Ich habe auch ein kleines Demo dazu geschrieben. Das fasst zwar im Prinzip nur die hier geposteten Infos zusammen, aber wenn Interesse besteht, werde ich das Demo gerne hier posten.

Ansonsten freue ich mich auch weiterhin über Infos, die zu diesem Thema beitragen! :P

Guido.

toms 16. Sep 2008 18:38

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Guido Eisenbeis
Ich habe auch ein kleines Demo dazu geschrieben. Das fasst zwar im Prinzip nur die hier geposteten Infos zusammen, aber wenn Interesse besteht, werde ich das Demo gerne hier posten.

Hallo Guido, kannst das Demo gerne hier posten.

Neutral General 16. Sep 2008 18:38

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Guido Eisenbeis
Nun habe ich mich entschieden, dass die FillChar-Lösung die richtige für mein Problem ist und werde sie verwenden.

Vergiss das Finalize nicht :stupid: ;)

Guido Eisenbeis 16. Sep 2008 21:36

Re: Record zurücksetzen (löschen)
 
Hier das Demo:

Delphi-Quellcode:
unit Unit2;

(*
  ==============================
  Record-Variable schnell leeren
  ==============================

  Um alle Felder einer Record-Variablen schnell und einfach zu leeren,
  kann man die Routinen "Finalize" + "FillChar" benutzen. Diese
  wurden in diesem Demo in der Prozedur "Clear" zusammengefasst.
  Dabei werden String-Variablen auf leer, Zahlen-Variablen auf Null,
  ... gesetzt.

  Auch verschachtelte Records können damit geleert werden. Das heißt,
  Records die selbst wieder Records enthalten.

  In der Methode Clear müssen vor dem abschließenden FillChar-Befehl
  alle (dynamischen) Daten im Record freigegeben werden. Finalize
  selbst berücksichtigt nur die referenzgezählten Daten.

  Speicherbereiche, die mit New o. ä. angelegt wurden, sowie Objekte,
  die durch Aufruf eines Konstruktors erzeugt wurden, muss man also
  auch wieder manuell freigeben.


  Tipp von Hawkeye219 auf [url]www.delphipraxis.net[/url], in meinem Thread
  "Sonstige Fragen zu Delphi \ Record zurücksetzen (löschen)".

  Forum-Thread und Demo von Guido Eisenbeis, 2008-09-14.
*)

interface

uses
  Windows;

Type
  TMyRecord = record
    Test_1    : string;
    Test_2    : string;
    Integer_1 : Integer;
    Integer_2 : Integer;
    FindData: TWIN32FINDDATA;
    procedure Clear();
  end;


implementation


// Finalize + FillChar Lösung
procedure TMyRecord.Clear();
begin
  Finalize(Self);
  FillChar(Self, SizeOf(Self), 0);
end;

end.
Beispiel:
----------

Delphi-Quellcode:
unit Unit1;

...

implementation

{$R *.dfm}

uses
  Unit2;

// Einige Testwerte setzen
procedure SetTestValues(var AMyRecord: TMyRecord);
begin
  AMyRecord.Test_1 := 'Hallo';
  AMyRecord.Test_2 := 'Welt!';
  AMyRecord.Integer_1 := 9;
  AMyRecord.Integer_2 := 2008;
  AMyRecord.FindData.cFileName := 'TestVal';
end;


// String für Ausgabe formatieren
function PrepareMsg(AMyRecord: TMyRecord): string;
begin
  Result :=
    'Test_1:   ' + '>' + AMyRecord.Test_1 + '<' + #13#10+
    'Test_2:   ' + '>' + AMyRecord.Test_2 + '<' + #13#10+
    'Integer_1:   ' + IntToStr(AMyRecord.Integer_1) + #13#10+
    'Integer_2:   ' + IntToStr(AMyRecord.Integer_2) + #13#10+
    'FindData.cFileName:   ' + '>' + AMyRecord.FindData.cFileName + '<';
end;


procedure TForm1.Button1Click(Sender: TObject);
var
  MyRecord: TMyRecord;
begin
  // Undefinierte Anfangswerte (beim ersten Test erscheinen hier Zufallswerte).
  ShowMessage(PrepareMsg(MyRecord));

  // Beispielwerte zuweisen
  SetTestValues(MyRecord);
  ShowMessage(PrepareMsg(MyRecord));

  // Alle Record-Felder mit "FillChar" leeren.
  MyRecord.Clear;

  ShowMessage(PrepareMsg(MyRecord));

  // Beispielwerte zur Kontrolle erneut zuweisen
  SetTestValues(MyRecord);
  ShowMessage(PrepareMsg(MyRecord));
end;
Guido.

smallsmoker 16. Sep 2008 21:51

Re: Record zurücksetzen (löschen)
 
Zitat:

// Undefinierte Anfangswerte (beim ersten Test erscheinen hier Zufallswerte).
das stimmt so nicht ganz, da du dein record nicht initialisierst vorm ersten aufruf zeigen die pointer
noch auf speicherbereiche in denen der "müll" von anderen anwendungen rumliegt.

naja soweit glaube ich es verstanden zu haben.

mfg smallsmoker

SubData 17. Sep 2008 07:10

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von smallsmoker
noch auf speicherbereiche in denen der "müll" von anderen anwendungen rumliegt.

Was ggf. direkt zu einer Zugriffsverletzung führen kann.

Guido Eisenbeis 17. Sep 2008 20:15

Re: Record zurücksetzen (löschen)
 
Hallo smallsmoker, willkommen in der Runde. :-D

Hab ich mich da nicht deutlich genug ausgedrückt ? :gruebel:

Zitat:

da du dein record nicht initialisierst vorm ersten aufruf
= nicht- (oder un-) definierte Anfangswerte.

Zitat:

zeigen die pointer noch auf speicherbereiche in denen der "müll" von anderen anwendungen rumliegt.
= Zufallswerte.

Somit haben wir beide das Gleiche gesagt, nur anders ausgedrückt. Ich dachte, dass Programmierer das so interpretieren. :P

Guido.

SubData 17. Sep 2008 21:37

Re: Record zurücksetzen (löschen)
 
Zufallswerte sind nicht undefinierte Werte.

Da gibt es riesige Unterschiede, aber das würde das Thema hier sprengen ;-)

Guido Eisenbeis 17. Sep 2008 21:57

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von SubData
Zufallswerte sind nicht undefinierte Werte.

Warum erwähnst du das? Das hat niemand behauptet!

Guido.

SubData 18. Sep 2008 07:33

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Guido Eisenbeis
Zitat:

zeigen die pointer noch auf speicherbereiche in denen der "müll" von anderen anwendungen rumliegt.
= Zufallswerte.


Guido Eisenbeis 18. Sep 2008 09:07

Re: Record zurücksetzen (löschen)
 
Und?

SubData 18. Sep 2008 09:11

Re: Record zurücksetzen (löschen)
 
Nix und, ich wollte nur darauf hinweisen, dass Zufallswerte und undefinierte Werte nicht das Gleiche sind :)

Guido Eisenbeis 26. Sep 2008 19:33

Re: Record zurücksetzen (löschen)
 
Bin über die Funktion "ZeroMemory" gestolpert. Wenn man die anstatt "FillChar" benutzt, hat das Vor- oder Nachteile?

Guido.

Neutral General 26. Sep 2008 19:39

Re: Record zurücksetzen (löschen)
 
Soweit ich weiß, macht das keinen Unterschied.

toms 26. Sep 2008 19:39

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von Guido Eisenbeis
Bin über die Funktion "ZeroMemory" gestolpert. Wenn man die anstatt "FillChar" benutzt, hat das Vor- oder Nachteile?

Guido.

Ein Blick in den Source-Code verrät folgendes:

Delphi-Quellcode:
procedure ZeroMemory(Destination: Pointer; Length: DWORD);
begin
  FillChar(Destination^, Length, 0);
end;

grenzgaenger 26. Sep 2008 19:46

Re: Record zurücksetzen (löschen)
 
hab zwar nicht den gesamten thread gelesen, aber bei der methode finalize/zeromemory, sollt man vorsichtig sein. wenn man so etwas anwendet muss man immer einen konkreten record im hinterkopf haben, sonst bekommt man die schönsten speicherlöcher ... :drunken:

Guido Eisenbeis 26. Sep 2008 19:47

Re: Record zurücksetzen (löschen)
 
Zitat:

Zitat von toms
Delphi-Quellcode:
procedure ZeroMemory(Destination: Pointer; Length: DWORD);
begin
  FillChar(Destination^, Length, 0);
end;

Hua, hua, hua, :spin: ich lach mich kaputt :cheer:

Das ist ja der Hammer und die Frage hat sich somit erledigt! *lol*

Vielen Dank euch beiden!

Guido.

Rosenwehr 9. Okt 2008 07:20

Re: Record zurücksetzen (löschen)
 
Ich nutze Delphi2005Prof und möchte myrecord.clear() (s.o.) nutzen.

Beim compilieren erhalte ich: "E2029 'END' erwartet, aber 'PROCEDURE' gefunden". Der Cursor steht in Unit 2 hinter dem Wort procedure der Tmyrecord deklaration.

Type
TMyRecord = record
Test_1 : string;
Test_2 : string;
Integer_1 : Integer;
Integer_2 : Integer;
FindData: TWIN32FINDDATA;
procedure Clear();
end;


Sind spezielle Units einzubinden oder wird es in der Delphi-Version nicht unterstützt?

Daniel 9. Okt 2008 07:23

Re: Record zurücksetzen (löschen)
 
Diese Möglichkeit hast Du leider erst ab Delphi 2006.

Rosenwehr 9. Okt 2008 07:29

Re: Record zurücksetzen (löschen)
 
Danke für die schnelle Antwort.

Rosenwehr 9. Okt 2008 07:34

Re: Record zurücksetzen (löschen)
 
Wäre es möglich, eine compilierte Unit2 unter D2006 mit D2005 zu nutzen?

D. h. Bearbeitung der Unit1 unter D2005 und Zugriff auf die dcu (mit dem Record) vom D2006?

Wenn ja, gilt das auch für folgende Delphi-Versionen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:01 Uhr.
Seite 2 von 3     12 3      

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