Delphi - 树形视图数据对象需要被释放吗?

4

Delphi 2010 - 我有一个TreeView,大约有2000个节点。每个节点都有一个数据对象,指向一个记录。当我退出程序时,与数据对象相关联的内存是否会自动释放,还是我需要遍历每个节点并对其进行DISPOSE处理?


1
只有在您创建了数据对象背后的对象时,才需要释放它们。您所创建的内容,需要确保已被释放。系统创建的内容将由系统自行释放。Data属性不知道您放入其中的内容,它们只是指针。 - Jerry Dodge
将您的记录放入 TList<T> 中,在程序终止时,只需遍历列表并释放项目即可。如果使用对象,则 TObjectList<T> 更合适,因为它还可以在销毁列表时自动释放对象。 - whosrdaddy
1
是的,没错。对象占用的内存将在程序退出时返回给操作系统并被释放,但您应该手动释放这些对象。 - TLama
@TLama,是的,没错。在我看来,我永远不会让任何泄漏未被处理 :) - whosrdaddy
@whosrdaddy,我两个都不会做;我忘记回答问题的第二部分了 :) 已经修复。 - TLama
4个回答

3

通过Google搜索找到这个问题,没有找到我刚使用的解决方案,尽管这个问题已经有几年了,但我还是决定回答一下。

TTreeView有一个OnTreeDeletion方法,当树中的每个节点被删除时调用该方法,从而有机会释放/处理任何相关数据。

以下是我的代码:

procedure TfmMyForm.MyTreeDeletion(Sender: TObject; Node: TTreeNode);
var
  rci: TRecentCodeItem;
begin
  rci := node.data;

  if assigned(rci) then
    freeandnil(rci);
end;

我在节点中存储了一个类型为TRecentCodeItem的对象的指针。
我的情况与提问者的不同之处在于,我的树形视图不在主窗体上,因此我不能让Windows在应用程序关闭后自动清理内存。即使这样,我也不会这样做——我喜欢零内存泄漏。

2
TTreeNode类的Data属性是为您的私有需求而设计的。它是一个无类型指针,这使您可以随意在其中放置任何内容。
由于该属性是一个无类型指针,所以控件无法知道您放置在其中的内容的类型。因此,即使它想要销毁它,它也无法。因此,您需要确保您分配的内存被销毁。实质上,你是那个内存的所有者,控件不拥有它。
如何做到这一点当然完全取决于您。一种选择是拥有一个拥有与每个节点相关联的数据的单独容器。然后,您可以删除容器并让它删除数据。
如果您拥有难以在可用容器中复制的复杂树结构,则可能会很不方便。在这种情况下,您可能会选择自定义树视图以创建您定义的节点类型。该自定义节点类型可以负责分配和释放数据。OnCreateNodeClass是实现这一目标的关键。

让我确定我理解了这一点。尽管我的程序创建对象(特别是节点使用指向记录的数据属性),但除非我通过OnCloseQuery或类似事件处理程序处置这些实体,否则Windows不会“释放”这些内存,对吗? - user1009073
操作系统将在进程关闭时将其收回。操作系统那时会将一切都收回。 - David Heffernan

0

我使用了这个解决方案,也许它能帮助未来的某个人:

TTreeViewItemEx<TData: class> = class(TTreeViewItem)
private
    _dataObject: TData;
public
    destructor Destroy; override;
    property dataObject: TData read _dataObject write _dataObject;
end;

destructor TTreeViewItemEx<TData>.Destroy;
begin
    if Assigned(_dataObject) then
        _dataObject.Free;

    inherited;
end;

用法:

procedure UsageExample;
var
    node: TTreeViewItemEx<TData>;
begin
    node := TTreeViewItemEx<TData>.Create(treeView);
    node.DataObject := TData.Create;
    node.Parent := treeView;
end;

0

是的,一旦您退出程序,数据就会被释放,因为对象驻留在应用程序运行的进程的同一内存空间中。无论如何,手动释放它们是一个好习惯,可以使用 Object.free 或更好的是 FreeAndNil(object)


1
"Free"和"Dispose"不可互换。 - David Heffernan
@DavidHeffernan 当然,你是对的。我编辑了我的回答。 - Floris
你修复它的方式不对。指向记录的指针。所以需要使用 Dispose - David Heffernan
@DavidHeffernan 实际上,你可以TTreeNode中存储一个对象。最好的做法可能是直接存储对象而不是记录指针,例如MyClass := TMyClass.Create;,然后稍后使用TMyClass(Node.Data).Free; - Floris
实际上我知道这一点。我在我的回答中说过,“它是一个未类型化的指针,这使你可以在其中放置任何你喜欢的东西。”但由于提问者明确而明确地说明了节点中的内容是“指向记录的指针”,所以你建议调用Free是不合适的。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接