gpt4 book ai didi

delphi - 对象的 VirtualTreeView 内存泄漏

转载 作者:行者123 更新时间:2023-12-03 19:30:03 25 4
gpt4 key购买 nike

我正在使用 Cosmin Prund 提供的代码在这个post因为它符合我的需要,但是我经常遇到内存泄漏,我无法弄清楚如何释放它的节点 TNode包含 TObjectList 的对象反过来,最后一个也可以包含TNode还包含 TObjectList依此类推……虽然我是某种递归,

据我所知,释放 VirtualTreeView 中的节点据此link该节点需要在 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.

内存泄漏报告:

enter image description here

最佳答案

Cosmin 的代码不打算让 TreeView 节点拥有 TNode对象。我认为在他的帖子中,您应该坚持 Root对象并在树被销毁后将其销毁。

在 Cosmin 的代码中,TNode对象由包含它们的对象列表所有。一直到由创建它的任何人拥有的根节点。你也可以这样做。您必须记住根对象,并停止破坏 TNode TreeView 节点被破坏时的对象。

如果你想让 TreeView 拥有 TNode对象然后你可以做到这一点。但是你需要清楚所有权。你不能有 TreeView 对象列表拥有这些对象,就像您当前所做的那样。如果 TreeView 将成为所有者,那么您需要设置 OwnsObjectsFalse在对象列表中。或者更好地切换到 TList<TNode> .

因此,总而言之,您当前的代码给出了每个 TNode反对两个所有者。 TreeView 节点和拥有对象列表。对象需要只有一个所有者。您需要在两个选项之间进行选择。

关于delphi - 对象的 VirtualTreeView 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28901084/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com