delphi OwnerData TListView泄漏项的内存,是否添加?

68bkxrlz  于 2023-04-11  发布在  其他
关注(0)|答案(1)|浏览(168)

以下代码将在关闭OwnerData TListView时报告内存泄漏:

procedure TForm1.Button1Click(Sender: TObject);
begin
    ReportMemoryLeaksOnShutdown := True;
    ListView1.Items.Add.Caption := 'blah';
end;

我从来没有意识到在OwnerData模式下禁止执行常规Items.Add
更糟糕的是,一旦添加了内存,内存泄漏是不可避免的吗?
手动Free(适用于Item[0]Items)会导致崩溃。
后续的ListView1.OwnerData := False无法求解。

kq4fsx7k

kq4fsx7k1#

我从来没有意识到在OwnerData模式下禁止执行常规Items.Add
它本身并不是严格禁止的,但它会“默默地失败”,不会向您报告任何错误。
TListView.Items.Add() * 无条件地 * 创建一个新的TListItem对象,然后将其传递给Win32 ListView_InsertItem() API,作为插入LVITEM项的LPARAM。然而,在OwnerData=True模式下插入将失败,不幸的是TListView没有检查该条件,因此它没有释放TListItem,因此泄漏。
实际上我会认为这是TListView中的一个bug。当不允许Items.Add()(和其他相关方法)时,我会期望raise是一个异常。我猜不是。在VCL文档中只有这个警告:
https://docwiki.embarcadero.com/Libraries/Alexandria/en/Vcl.ComCtrls.TCustomListView.Items
警告:如果列表视图为虚拟模式,则Items只读,详情请参见OwnerData
https://docwiki.embarcadero.com/Libraries/en/Vcl.ComCtrls.TCustomListView.OwnerData
...但是,**您必须使用OnDataOnDataFindOnDataHintOnDataStateChange事件处理程序来管理虚拟列表视图的项目。**例如,如果要显示复选框,则必须显式为列表项目的StateIndex属性提供值。

创建虚拟列表视图时,必须将ItemsCount属性设置为虚拟列表中的项目数。

这意味着,在使用OwnerData=True时,您根本不应该使用Items.Add()(和其他方法)。您应该将Items.Count属性设置为您想要显示的项目的 * 数量 *,然后在ListView要求您提供数据时,使用OnData...事件为每个项目提供数据。
更糟糕的是,一旦添加了内存,内存泄漏是不可避免的吗?
是的,因为TListItem永远不会被VCL释放,所以您必须手动释放它。
手动释放(对于项目[0]和项目)导致崩溃。
正确,因为泄漏的TListItem实际上并不在Items列表中。指向泄漏的TListItem的 * 唯一 * 有效指针是Items.Add()返回给您的指针。
后续的ListView1.OwnerData := False未解决。
为什么要这样做呢?ListView在那时并不知道任何关于泄露的TListItem的信息。

**更新:**我现在已经向Embarcadero提交了一份关于此问题的bug报告:

RSP-41256: Memory leak in TListView when OwnerData=True and Items.Add() is called

相关问题