首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对象的VirtualTreeView内存泄漏

对象的VirtualTreeView内存泄漏
EN

Stack Overflow用户
提问于 2015-03-06 14:38:15
回答 1查看 754关注 0票数 1

我使用Cosmin Prund在这个post中提供的代码,因为它符合我的需要,但是我经常会遇到内存泄漏,并且我无法确定如何释放节点,它是包含TObjectListTNode对象。最后一个可以包含包含TObjectListTNode,等等……我想这是某种递归,

我知道要释放VirtualTreeView中的节点,根据这个link,需要对节点进行验证,并在OnFreeNode事件中完成这些代码,返回无效的指针操作,当然还有内存泄漏报告:

代码语言:javascript
复制
procedure TfrmFichePermission.VSTFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  AObject:TObject;
  ANode: TNode;
begin
  AObject := TObject(VST.GetNodeData(Node)^);
  ANode := TNode(AObject);
  ANode.Free;
end;

这是再现内存泄漏的完整示例。

代码语言:javascript
复制
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.

内存泄漏报告:

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-03-07 08:29:37

Cosmin的代码不打算让树形视图节点拥有TNode对象。我认为在他的帖子中,你应该保留Root对象,并在树被毁后销毁它。

在Cosmin的代码中,TNode对象属于包含它们的对象列表。一直走到根节点,它是由创建它的任何东西所拥有的。你也可以这么做。您必须记住根对象,并在树状视图节点被销毁时停止销毁TNode对象。

如果您想让树视图拥有TNode对象,那么您可以这样做。但你得弄清楚所有权。不能像当前那样让树形视图和对象列表拥有对象。如果树视图将是所有者,则需要在对象列表中将OwnsObjects设置为False。或者更好地切换到TList<TNode>

因此,概括地说,您现在的代码为每个TNode对象提供了两个所有者。树形视图节点和拥有的对象列表。对象需要恰好有一个所有者。你需要在这两种选择中做出选择。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28901084

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档