【问题标题】:Delphi 2007 MDI Form Destroy Sequence IssueDelphi 2007 MDI 表单销毁序列问题
【发布时间】:2015-06-27 18:47:10
【问题描述】:

我有一个奇怪的问题,我似乎无法弄清楚。我有一个 MDI 子窗体,上面有一个 TListView 组件。在这个列表视图中,我添加了一些带有指向相关对象的数据属性的列表项。在 OnFormDestroy 事件中,我执行类似于以下的操作来清理这些对象:

Procedure TMDIChildForm1.FormDestroy(Sender: TObject);
Begin
  For I := 0 To lvLabour.Items.Count - 1 Do
    TLabourItem(lvLabour.Items[I].Data).Free;
  lvLabour.Items.Clear;
End;

现在,如果我关闭表单本身但让应用程序保持打开状态,这可以正常工作。它将遍历每个项目以释放​​关联的对象。但是,如果我在没有先关闭 MDI 表单的情况下完全关闭应用程序,当它到达上面的代码时,项目计数为 0。这意味着在调用 FormDestroy 方法之前从列表中清除了项目。

因为只有在应用程序关闭时才会发生这种情况,所以没有内存泄漏。我只是将应用程序设置为在调试时显示内存泄漏,当我收到内存泄漏消息并且无法弄清楚原因时,它让我很恼火。

【问题讨论】:

    标签: delphi memory-leaks


    【解决方案1】:

    发生这种情况是因为无论出于何种原因,终止进程都会在您的代码运行之前清除列表视图。但是有更好的方法来处理这个问题。好吧,有一些更好的诚实方式。

    从离你最近的地方开始,你应该使用列表视图的OnDeletion 事件来执行项目整理。每当删除列表项时都会触发此事件。您的事件处理程序将具有以下原型:

    procedure ListView1Deletion(Sender: TObject; Item: TListItem);
    

    在此事件处理程序中,对 Item.Data 中保存的对象调用 Free。这样一来,无论列表及其项如何被销毁,您都可以确保关联的数据被销毁。

    我推荐的另一种方法涉及更多工作。不要让列表项包含对数据的引用,而是使用虚拟列表视图。在这种操作模式下,当列表视图控件需要绘制项目,或者查询它们的属性和状态时,它会调用控件的事件来按需获取信息。这避免了您需要将数据对象的生命周期与显示它的 GUI 的生命周期结合起来。

    【讨论】:

    • 取决于 ListView 项目与它们所引用的数据的关系,以及数据是显示给用户还是仅供私人使用,在虚拟模式下使用 ListView 可能会有点过头了情况。一个较小的更改是将实际数据项存储在单独的 TList 中,然后继续使用 TListItem.Data 来引用它们以方便。但是当需要释放它们时,循环遍历 TList 而不是 TListView。
    • 虽然我通常同意在数据项存储在 ListView 本身中时在 OnDeletion 上使用,但我也建议谨慎使用,因为有些版本 OnDeletion 已被破坏,要么根本没有触发,或者在错误的时间或以错误的顺序触发。
    • @David:谢谢...我什至没有意识到 TListViews 有一个 OnDeletion 事件,而我已经使用 Delphi 15 年了!实际上,我仍然很好奇为什么在处理这个特定示例时会清除列表项,但是哦,好吧。
    • 我确信我们可以解决这个问题,但我找不到这样做的动力!
    • @RemyLebeau:我将稍微测试一下 OnDeletion 事件,因为它似乎是最快的更改。虽然我同意设置一个单独的 TList 可能更稳定,但考虑到我们的应用程序在任何地方都做这些事情,它也需要做更多的工作。但是感谢您的提示!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    相关资源
    最近更新 更多