簡體   English   中英

VirtualTreeView對象的內存泄漏

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM