【问题标题】:MFC C++ CListCtrl - deleting all items does not reclaim memoryMFC C++ CListCtrl - 删除所有项目不会回收内存
【发布时间】:2018-09-26 22:26:24
【问题描述】:

我根本不是 MFC 方面的专家,但我被派去一个项目来改进我们的一个应用程序中的 GUI。我正在使用 CListCtrl 构建一个对话框并看到内存问题,即使我正在显示的列表通常包含不超过 200 行。有 4 列,我使用 SetItemData 为每一行附加一个关联的 int 值以进行过滤。

过滤时,我首先调用 DeleteAllItems() 重新填充列表,然后循环以仅填充通过过滤器的数据。当我在系统任务管理器对话框的“性能”选项卡中查看时,我看到对话框打开时已占用内存。似乎比我想象的要多,但无论如何。根据任务管理器性能选项卡,当我过滤时,如果所选过滤器没有显示任何内容,则系统永远不会回收内存。当我更改过滤器以显示一些行时,我看到占用了更多内存。我从来没有看到内存回馈给系统。如果我继续过滤,我最终会看到内存使用量几乎达到完全使用,并且我会看到 MFC 提出的内存不足对话框。

当我只是在数据的完整(未过滤)视图中上下滚动很多时,我也看到了这个内存不足对话框。对于每次滚动,重新绘制列表控件有点慢,并且“性能”选项卡中的内存使用量上升,即使我没有添加任何数据。

有人对这里可能发生的事情有感觉吗?我现在很难过。以下基本上是我在我的代码中所做的。我不是以其他方式管理视图:

m_ListCtrl.DeleteAllItems();
for (int i=0; i<mylist.size(); i++)
{
    // here I get all the data from the current record in mylist, one of them being an int value iSecs.
    ...

    // insert data item
    int row = m_ListCtrl.InsertItem(i, sTimeStamp.c_str());
    BOOL ok = m_ListCtrl.SetItem(i, 1, sErrorCode.c_str());
    ok = m_ListCtrl.SetItem(i, 2, sErrorLevel.c_str());
    ok = m_ListCtrl.SetItem(i, 3, sDescription.c_str());
    // set the timestamp seconds as item data for later filtering for display
    ok = m_ListCtrl.SetItemData(row, (DWORD_PTR)iSecs);
}

【问题讨论】:

  • 这里我得到了mylist中当前记录的所有数据 问题出在哪里?您正在进行的 MFC 调用只是各种LVM_xxx 消息的包装器(例如 LVM_DELETEALLITEMS)。他们实际上什么都不做。
  • DeleteAllItems 执行“浅”删除。值得注意的是,它不会删除 LVITEMlParam 成员指向的任何内容。 piColFmt 也是如此。发布的代码似乎没有泄漏任何资源。我们需要看到minimal reproducible example
  • 您指的是哪个“内存不足对话框”?代码中一定有你没有在此处显示的内容。
  • 不,内存不足对话框是 MFC 弹出的对话框。我已经看到类似的对话框,例如当我尝试创建一个具有 IDD 定义的对话框时,该 IDD 定义存在于 resource.h 中,但其对话框定义在 .rc 文件中不存在。他们这样做是为了避免应用程序崩溃,但仍要通知用户出现问题。
  • IInspectable - 感谢您的链接。我会看一下,让你知道我的发现。

标签: c++ visual-studio-2010 memory-leaks mfc clistctrl


【解决方案1】:

调用free()(或delete)时,堆内存通常不会返回给操作系统。它保留在堆中。另见this answer。因此,在第一次填充/删除所有操作时,您将看到分配的内存增加。但在随后的循环中,内存使用应该相当稳定。

Microsoft 的 MFC 库已经存在十多年了,如果 CListCtrl::DeleteAllItems() 出现内存泄漏,它会在 90 年代被发现。

你可以在程序with a few API calls查看内存使用情况。

内存泄漏可能是由这行引起的:

ok = m_ListCtrl.SetItemData(row, (DWORD_PTR)iSecs);

在 MFC 中项目数据是用户清理的责任。在调用 API 删除列表项之前,您需要遍历列表中的每个项目以释放​​(或删除)用户数据。当然你也可以通过其他方式释放分配的数据。

随着您的程序不断地在列表中添加和删除项目,它会泄漏与每个列表条目关联的 ItemData。

【讨论】:

  • 虽然是真的,但它并没有给出问题的答案,为什么代码确实最终会耗尽内存。
猜你喜欢
  • 2013-06-05
  • 1970-01-01
  • 1970-01-01
  • 2011-04-25
  • 2013-11-22
  • 1970-01-01
  • 2020-02-11
  • 2023-03-18
相关资源
最近更新 更多