【发布时间】:2015-03-06 14:38:15
【问题描述】:
我在这个post 中使用Cosmin Prund 提供的代码,因为它符合我的需要,但是我经常遇到内存泄漏,我无法弄清楚如何释放包含@ 的TNode 对象的节点987654326@ 反过来,最后一个也可以包含TNode,也可以包含TObjectList 等等......我虽然是某种递归,
据我所知,根据此link 释放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.
内存泄漏报告:
【问题讨论】:
-
TObjectList默认拥有对象。 -
为什么先转换成 TObject 再转换成 TNode?为什么不直接到 TNode?我们怎么知道 TNode 是什么?如果那里有错误怎么办?为什么只发布少量代码。为一个完整并展示了问题的控制台应用程序发布一个简短的 .dpr 是很容易的。如果你这样做了,你会在 10 分钟内得到答案。
-
@David Heffernan 你知道我正要问同样的问题,关于为什么投射 twise TObject 而不是 TNode :) 对于示例,它与我在上面提到的帖子 + OnFreeNode 事件的代码相同所以我只发布额外的代码......
-
您真正的问题不是内存泄漏,而是无效的指针操作。解决这个问题,您的内存泄漏也很可能会得到解决。
-
我们没有收到有关问题编辑的通知
标签: delphi memory-leaks virtualtreeview