Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi TVirtualTreeView gibt nicht alles frei (https://www.delphipraxis.net/35167-tvirtualtreeview-gibt-nicht-alles-frei.html)

hitzi 3. Dez 2004 12:52


TVirtualTreeView gibt nicht alles frei
 
Hallo,

ich nutze einen VirtualStringTree im Spaltenmodus.

Datenrecord:

Delphi-Quellcode:
type
  PTreeData = ^TTreeData;
  TTreeData = record
    FName : String;
    FPrivat : String;
    FMobile : String;
    FWork : String;
    FOther : String;
    FFax : String;
    FEmail : String;
    FHomepage : String;
    FOrganisation : String;
    FPosition : String;
    FStreet : String;
    FZIP : String;
    FCity : String;
    FState : String;
    FCountry : String;
    FNotes : String;
    fLuid : string;
  end;
Procedure zum Füllen mit Daten:
Delphi-Quellcode:
procedure TframeContacts.LoadContacts;
var Data: PTreeData;
    Node : PVirtualNode;
    i : integer;
begin
  vstContacts.BeginUpdate;
  try
    vstContacts.Clear;
    for i := 0 to PIM.RecordCount - 1 do
    begin
      Node := vstContacts.AddChild(nil);
      Data := vstContacts.GetNodeData(Node);
      Data^.FName := PIM.fvCard[i].FirstName + #32 + PIM.fvCard[i].Name;
      Data^.FPrivat := PIM.fvCard[i].TelHome;
      Data^.FMobile := PIM.fvCard[i].TelCell;
      Data^.FWork := PIM.fvCard[i].TelWork;
      Data^.FOther := PIM.fvCard[i].TelOther;
      Data^.FFax := PIM.fvCard[i].TelFax;
      Data^.FEmail := PIM.fvCard[i].Email;
      Data^.FHomepage := PIM.fvCard[i].URL;
      Data^.FOrganisation := PIM.fvCard[i].Organisation;
      Data^.FPosition := PIM.fvCard[i].Title;
      Data^.FStreet := PIM.fvCard[i].Street;
      Data^.FZIP := PIM.fvCard[i].ZIP;
      Data^.FCity := PIM.fvCard[i].City;
      Data^.FState := PIM.fvCard[i].State;
      Data^.FCountry := PIM.fvCard[i].Country;
      Data^.FNotes := PIM.fvCard[i].Note;
      Data^.fLuid := PIM.fvCard[i].Luid;
    end;
  finally
    vstContacts.EndUpdate;
  end;
end;
Procedure zum freigeben der Daten:

Delphi-Quellcode:
procedure TframeContacts.vstContactsFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: PTreeData;
begin
  Data:=vstContacts.GetNodeData(Node);
  if Assigned(Data) then begin
    Data.FName := '';
    Data.FPrivat := '';
    Data.FMobile := '';
    Data.FWork := '';
    Data.FOther := '';
    Data.FFax := '';
    Data.FEmail := '';
    Data.FHomepage := '';
    Data.FOrganisation := '';
    Data.FPosition := '';
    Data.FStreet := '';
    Data.FZIP := '';
    Data.FCity := '';
    Data.FState := '';
    Data.FCountry := '';
    Data.FNotes := '';
    Data.fLuid := '';
  end;
end;
Ich lasse den Treeview mit Daten füllen und beim Destroy des Frames TframeContacts wird alles freigegeben auch. Theoretisch auch die Nodes. Leider nur theoretisch. Mit dem Taskmanager überwacht wird schnell erkenntlich, dass mit jedem Füllen/Freigeben rund 30KB nicht freigegeben werden.
Lasse ich das Erstellen der Nodes weg (TframeContacts.LoadContacts wird auskommentiert) wird jedes mal der Speicher beim Destroy des Frames auf dem Ursprungswert zurückgesetzt - sprich es wird alles was auf dem Frame war wieder freigegeben.
Fazit: Die Daten der Nodes werden nicht freigegeben. Wieso? Die Procedure TframeContacts.vstContactsFreeNode wird korrekt aufgerufen, wenn man das Programm im Einzelschritt durchgeht.

[EDIT]Ich weiß warum nicht alle Nodes freigegeben werden. Es sind 78 Zeilen im VirtualTreeView - die Procedure FreeNode wird aber nur insgesamt 19 mal aufgerufen. 59 Datensätze verbleiben also im Speicher.
Wieso ist das so?[/EDIT]

Gruss

hitzi 3. Dez 2004 13:35

Re: TVirtualTreeView gibt nicht alles frei
 
Um's mit den Worten des Entwicklers (Mike) zu erklären:

Zitat:

The key for VT to be so fast is to do things only if necessary. So, beside other things, it keeps a flag that tells it whether a node has been used or not. "Used" in this context means a nodes has been touch either because there was an iteration including that node or it has been displayed at least once. This flag indicates a socalled initialzed node and only initialized nodes are also passed to the application via OnFreeNode when they are about to be destroyed.

What you can do is to initialize a node explicitely (ValidateNode) or use the native way to VT (OnInitNode, OnInitChildren) and fill your data only when you initialize a node.
Ein vstContacts.ValidateNode(node, False); beim Datenfüllen erfüllt den Zweck.

Gruss

drchaos 10. Jul 2007 16:45

Re: TVirtualTreeView gibt nicht alles frei
 
Zitat:

Datenrecord:

Delphi-Quellcode:
type
  PTreeData = ^TTreeData;
  TTreeData = record
    FName : String;
    FPrivat : String;
    FMobile : String;
    FWork : String;
    FOther : String;
    FFax : String;
    FEmail : String;
    FHomepage : String;
    FOrganisation : String;
    FPosition : String;
    FStreet : String;
    FZIP : String;
    FCity : String;
    FState : String;
    FCountry : String;
    FNotes : String;
    fLuid : string;
  end;

Eine Frage: Wenn in diesem Datenrecord ausschließlich Felder mit konstanter Größe vorhanden wären, könnte ich doch auf die Freigabe der Knoten im Ereignis OnFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode) verzichten, nicht wahr?

Hintergrund: Bei 50000 und mehr Knoten dauert mir die Freigabe per "Fxyz := ''" oder "Finalize(NodeData^)" zu lange.

Kann ich also das Freigeben auslassen, wenn ich stattdessen die Strings mit fester Länge deklariere, z.B. FName : String[50] ?
(Es wäre auch keine großartige Speicherverschwendung, weil alle Zeichenketten eh ungefähr gleiche Länge haben werden)

edit:
ok, im VirtualTreeView-Doc steht:
Zitat:

TVirtualStringTree.OnFreeNode Event

Triggered when a node is about to be freed. This is the ideal place to free/disconnect your own data you associated with Node. Keep in mind, that data which is stored directly in the node does not need to be free by the application. This is part of the node record and will be freed when the node is freed. You should however finalize the data in such a case if it contains references to external memory objects (e.g. variants, strings, interfaces).
So etwas wie String[50] wird als Konstante ins Record geschrieben, ja? Oder erzeugt Delphi dann trotzdem Pointer, und reserviert Speicher außerhalb der Struktur?

nochmal edit:
Zitat:

Onlinehilfe Delphi5 zum Thema "Statische Arrays"
Ein Array der Form array[0..x] of Char wird als nullbasiertes Zeichen-Array bezeichnet, da sein Index bei 0 beginnt. Nullbasierte Zeichen-Arrays werden zum Speichern von nullterminierten Strings verwendet und sind kompatibel mit PChar-Werten. Informationen hierzu finden Sie unter Nullterminierte Strings.
Ok, Char-Arrays sind erwartungsgemäß statisch... ist denn nun String[50] äquivalent zu array[0..49] of Char?


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