Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   MemoryLeak bei VirtualStringtree (https://www.delphipraxis.net/171942-memoryleak-bei-virtualstringtree.html)

youuu 3. Dez 2012 17:59

MemoryLeak bei VirtualStringtree
 
Hi, EurekaLog zeigt mir beim schließen immer ein MemoryLeak an von den Daten des Vst.

Die Daten des Vst werden so freigegeben.

Delphi-Quellcode:
procedure Tfrm_start.VstFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
Var
  Liste: Tliste;
begin
  Liste := Tliste(Vst.GetNodeData(node)^);
  Liste.Free;
end;
Muss das irgendwie noch speziell aufgerufen werden?

uligerhardt 3. Dez 2012 18:06

AW: MemoryLeak bei VirtualStringtree
 
Zitat:

Zitat von youuu (Beitrag 1194166)
Hi, EurekaLog zeigt mir beim schließen immer ein MemoryLeak an von den Daten des Vst.

Die Daten des Vst werden so freigegeben.

Delphi-Quellcode:
procedure Tfrm_start.VstFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
Var
  Liste: Tliste;
begin
  Liste := Tliste(Vst.GetNodeData(node)^);
  Liste.Free;
end;
Muss das irgendwie noch speziell aufgerufen werden?

Schuss ins Blaue: Ist der Destruktor von TListe auch virtuell?
Im Zweifelsfall wäre mal die Deklaration von TListe interessant. Zeigt EurekaLog nicht mehr Details an, was genau übrig bleibt?

youuu 3. Dez 2012 18:08

AW: MemoryLeak bei VirtualStringtree
 
Es wurde kein Destruktor in TListe extra erstellt, da es sich nur um normale Strings dort handelt.

shmia 3. Dez 2012 18:44

AW: MemoryLeak bei VirtualStringtree
 
Der Code sollte besser so aussehen:
Delphi-Quellcode:
procedure Tfrm_start.VstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  P: ^TObject;
begin
  P := Sender.getNodeData(Node);
  if Assigned(P) then
  begin
      P^.Free;
      P^ := nil; // zur Sicherheit
  end;
end;
Dass du "Vst" anstatt "Sender" verwendet hat, kann natürlich böse ins Auge gehen.
Eventuell lässt sich das noch so vereinfachen: (kann's nicht testen mangels VirtualTree Komponente)
Delphi-Quellcode:
procedure Tfrm_start.VstFreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
  P: ^TObject;
begin
  P := Sender.getNodeData(Node);
  FreeAndNil(P^);
end;

himitsu 3. Dez 2012 18:47

AW: MemoryLeak bei VirtualStringtree
 
Du hast wirklich statt der Objektreferenz einen Zeiger auf eine Variable mit der Objektreferenz in NodeData drin?

Und wie sind die TList-Instanzen dort reingekommen?

youuu 3. Dez 2012 19:26

AW: MemoryLeak bei VirtualStringtree
 
War die Frage an mich gerichtet Himutsu?

DeddyH 3. Dez 2012 19:32

AW: MemoryLeak bei VirtualStringtree
 
Vermutlich, Du dereferenzierst ja bereits im Ausgangspost.

youuu 4. Dez 2012 12:23

AW: MemoryLeak bei VirtualStringtree
 
Hm, weiß gerad enicht was damit gemeint ist, da ich mich an ein damaliges Tutorial gehalten habe.

himitsu 4. Dez 2012 12:42

AW: MemoryLeak bei VirtualStringtree
 
Zitat:

Zitat von youuu (Beitrag 1194263)
Hm, weiß gerad enicht was damit gemeint ist,

Das
Delphi-Quellcode:
^
in deinem Code.

Zitat:

Zitat von youuu (Beitrag 1194263)
da ich mich an ein damaliges Tutorial gehalten habe.

Dann würde ich einfach mal behaupten dieses Tutorial ist der totale Schrott, (auch wenn ich den rest davon jetzt natürlich nicht kenne)
oder du hast falsch abgeschrieben.

jbg 4. Dez 2012 17:32

AW: MemoryLeak bei VirtualStringtree
 
Zitat:

Zitat von shmia (Beitrag 1194174)
P := Sender.getNodeData(Node);
if Assigned(P) then

Unnütz. Sender.GetNodeData liefert hier nie nil, da weder Node=nil, noch Node=RootNode, noch NodeDataSize=0 ist, denn OnFreeNode wird für diese Konstellation nicht aufgerufen.


Zitat:

P^ := nil; // zur Sicherheit
Zur Sicherheit kann man den Speicherbereich direkt vor der Freigabe auch noch mit Nullen füllen.


Wenn man sich TVirtualNode mal anschaut:
Delphi-Quellcode:
TVirtualNode = packed record
  Index,
  ChildCount: Cardinal;
  // ...
  LastChild: PVirtualNode;
  Data: record end;
end;
dann sieht man, dass Sender.GetNodeData (vereinfacht) @Node.Data zurückliefert und das "P^ := nil" nichts anderes ist, als die 4 bzw. 8 Byte die hinter Data sind mit Nullen zu überschreiben. Und das direkt vor der Freigabe des Speicherbereichs.



**Sorry, hab mich nur gerade über eine viel zu langsame Migration geärgert, die, wenn ordnetlich programmiert, in 3 Minuten erledigt wäre und nicht wie jetzt, die ganze Nacht durchlaufen muss**

youuu 4. Dez 2012 18:22

AW: MemoryLeak bei VirtualStringtree
 
Hm also wenn ich es so mach:

Delphi-Quellcode:
procedure Tfrm_start.VstFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
Var
  Liste: ^Tliste;
begin
  Liste := Sender.GetNodeData(node);
  Liste^.Free;
end;
Bleibt der Leak bestehen.




Edit: So werden die Nodes hinzugefügt.

Delphi-Quellcode:
while not Query.Eof do begin
  Liste := TListe .Create;
  with Liste do begin
    ... Daten
  end;

  Node := FVst.AddChild(nil, KundenListe);
  Node.CheckType:= ctCheckBox;

  Query.Next;
end;
VstFreeNode muss ich nicht noch extra speziell aufrufen oder?

Zacherl 4. Dez 2012 19:04

AW: MemoryLeak bei VirtualStringtree
 
Gibt es bei dir Nodes, die nicht sichtbar sind? Rufe mal für jede Node, die du hinzufügst
Delphi-Quellcode:
ValidateNode(Node)
auf. Ich hatte das selbe Problem, was daran liegt, dass für nicht validated Nodes kein OnFreeNode Event aufgerufen wird. Nodes werden standardmäßig erst dann validiert, wenn sie mindestens einmal sichtbar waren.

youuu 4. Dez 2012 19:08

AW: MemoryLeak bei VirtualStringtree
 
Sind alle Sichtbar, kein Node ist unsichtbar.

Angeblich soll hier der Leak sein
Delphi-Quellcode:
 KundenListe := TKundenListe.Create;

youuu 4. Dez 2012 19:11

AW: MemoryLeak bei VirtualStringtree
 
Liste der Anhänge anzeigen (Anzahl: 1)
Siehe Anhang ein Bild, welches mich auch verwirrt. Wieso verursacht die System.pas auch Leaks? Und das alles erst nach dem füllen des VST's

Zacherl 4. Dez 2012 19:14

AW: MemoryLeak bei VirtualStringtree
 
Zitat:

Zitat von youuu (Beitrag 1194333)
Sind alle Sichtbar, kein Node ist unsichtbar.

Probier das
Delphi-Quellcode:
ValidateNode()
zur Sicherheit bitte trotzdem mal.

Zitat:

Zitat von youuu (Beitrag 1194333)
Angeblich soll hier der Leak sein
Delphi-Quellcode:
 KundenListe := TKundenListe.Create;

Das ist nur dann der Fall, wenn du deine Liste im OnFreeNode Event nicht wieder freigibst.

Ich weiß nicht, ob der VST damit zurecht kommt, wenn du direkt eine Klasse bzw. ein Objekt als Node nimmst. Ich gehe immer so vor:
Delphi-Quellcode:
type
  PMyNodeData = ^TMyNodeData;
  TMyNodeData = packed record
    Liste: TListe;
  end;
Dann irgendwo zur Initialisierung:
Delphi-Quellcode:
VST.NodeDataSize := SizeOf(TMyNodeData)


Nodes hinzufügen:
Delphi-Quellcode:
NodeData := VST.GetNodeData(VST.AddChild(nil));
NodeData^.Liste := TListe.Create;
// ..
Im OnFreeNode Event:
Delphi-Quellcode:
NodeData := Sender.GetNodeData(Node);
if Assigned(NodeData) then
begin
  NodeData^.Liste.Free;
  // Wenn du Strings oder Ähnliches direkt im TMyNodeData Record verwendest einfach noch ein
  // Finalize(NodeData^)
  // hinterherschieben
end;
Edit: Der Leak stammt nicht wirklich aus der System.pas. Es wird irgendwo ein UnicodeString erzeugt, welcher nicht mehr freigegeben wird. Lediglich die Funktion zum Erstellen eines neuen Strings befindet sich in der System.pas und wird per compiler magic oder was auch immer automatisch von Delphi aufgerufen, sobald du eine neue String Instanz erzeugst.

Edit: Was mir grade noch einfällt: Das Leak könnte sich auch in deiner TListe Klasse befinden. Prüf das am besten auch nochmal.

youuu 4. Dez 2012 19:34

AW: MemoryLeak bei VirtualStringtree
 
Edit: das war es, Leak ist entfernt. Danke Dir. Ich musste also nur das Objekt richtig einbinden


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