[英]VirtualTreeView Memory Leak with Objects
我使用所提供的代碼科斯明Prund在這個職位 ,因為它符合我的需要,但我經常收到內存泄漏,我無法弄清楚如何釋放它的節點TNode
對象包含TObjectList
反過來這最后還可以包含TNode
其中也包含TObjectList
等等...這是我的某種遞歸,
我知道要根據此鏈接在VirtualTreeView
釋放該節點,需要驗證該節點並在OnFreeNode
事件中完成該代碼,此代碼將返回無效指針操作,當然還有內存泄漏報告:
procedure TfrmFichePermission.VSTFreeNode(Sender: TBaseVirtualTree;
Node: PVirtualNode);
var
AObject:TObject;
ANode: TNode;
begin
AObject := TObject(VST.GetNodeData(Node)^);
ANode := TNode(AObject);
ANode.Free;
end;
這是重現內存泄漏的完整示例
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, System.Generics.Collections,
Vcl.StdCtrls;
type
TNode = class;
TForm1 = class(TForm)
VST: TVirtualStringTree;
Button1: TButton;
procedure VSTGetNodeDataSize(Sender: TBaseVirtualTree;
var NodeDataSize: Integer);
procedure VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
procedure Button1Click(Sender: TObject);
private
procedure AddNodestoTree(ParentNode: PVirtualNode; Node: TNode);
public
{ Public declarations }
end;
TNode = class
public
Name: string;
VTNode: PVirtualNode;
Sub: TObjectList<TNode>;
constructor Create(aName: string);
destructor Destroy; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TNode.Create(aName:string);
begin
Name := aName;
Sub := TObjectList<TNode>.Create;
end;
destructor TNode.Destroy;
begin
Sub.Free;
end;
procedure TForm1.AddNodestoTree(ParentNode: PVirtualNode; Node: TNode);
var SubNode: TNode;
ThisNode: PVirtualNode;
begin
ThisNode := VST.AddChild(ParentNode, Node); // This call adds a new TVirtualNode to the VT, and saves "Node" as the payload
Node.VTNode := ThisNode; // Save the PVirtualNode for future reference. This is only an example,
// the same TNode might be registered multiple times in the same VT,
// so it would be associated with multiple PVirtualNode's.
for SubNode in Node.Sub do
AddNodestoTree(ThisNode, SubNode);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Root: TNode;
begin
ReportMemoryLeaksOnShutdown := True;
VST.Clear;
//
Root := TNode.Create('Test1');
Root.Sub.Add(TNode.Create('Test2'));
Root.Sub.Add(TNode.Create('Test3'));
Root.Sub[1].Sub.Add(TNode.Create('Test4'));
Root.Sub[1].Sub.Add(TNode.Create('Test5'));
AddNodesToTree(nil, Root);
//
Root := TNode.Create('Test1');
Root.Sub.Add(TNode.Create('Test2'));
Root.Sub.Add(TNode.Create('Test3'));
Root.Sub[1].Sub.Add(TNode.Create('Test4'));
Root.Sub[1].Sub.Add(TNode.Create('Test5'));
AddNodesToTree(nil, Root);
//
end;
procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree;
var NodeDataSize: Integer);
begin
NodeDataSize := SizeOf(Pointer);
end;
procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
AObject:TObject;
ANode: TNode;
begin
AObject := TObject(VST.GetNodeData(Node)^);
ANode := TNode(AObject);
CellText := ANode.Name;
end;
end.
內存泄漏報告:
Cosmin的代碼無意讓樹視圖節點擁有TNode
對象。 我認為在他的帖子中,您打算保留Root
對象並在樹被破壞之后將其破壞。
在Cosmin的代碼中, TNode
對象由包含它們的對象列表所擁有。 一直到創建該對象的所有者所擁有的根節點。 您也可以這樣做。 您必須記住根對象,並在銷毀樹視圖節點時停止銷毀TNode
對象。
如果要讓樹視圖擁有TNode
對象,則可以這樣做。 但是您需要清楚所有權。 您無法像現在那樣擁有樹視圖和擁有對象的對象列表。 如果樹視圖將成為所有者,則需要在對象列表中將OwnsObjects
設置為False
。 甚至更好地切換到TList<TNode>
。
因此,總而言之,您當前的代碼為每個TNode
對象提供了兩個所有者。 樹視圖節點和擁有對象列表。 對象必須具有一個所有者。 您需要在兩個選項之間進行選擇。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.