7

我们正在从 VC8 升级到 VC10,并且发现了一些似乎与 CDialog 相关的内存泄漏。最简单的示例是使用以下代码演示的,该代码使用只有多个按钮的 CDialog。在 VC10 中会泄漏,但在 VC8 中不会:

for (int i = 0; i < 5000; ++i) {
  CDialog* dialog = new CDialog;
  dialog->Create(IDD_LEAKER, 0);
  dialog->DestroyWindow();
  delete dialog;
}

内存使用量不断上升,我们有大约 30 个按钮的示例对话框泄漏了 10s 的 Mb。

请注意,上面是一个测试示例,其中我们剥离了所有对话处理代码,在我们的实际代码中,我们有一个派生类并使用 PostNcDestroy()。

奇怪的是,以下代码示例都没有在 VC8 或 VC10 中泄漏:

CDialog* dialog = new CDialog;
for (int i = 0; i < 5000; ++i) {
  dialog->Create(IDD_LEAKER, 0);
  dialog->DestroyWindow();
}
delete dialog;

for (int i = 0; i < 5000; ++i) {
  CDialog* dialog = new CDialog;
  delete dialog;
}

我们在这里缺少什么?

4

1 回答 1

7

这似乎取决于 MFC 管理其句柄映射的方式:

从 CWnd::FromHandle 获得的 CWnd 的生命周期是多少?

如果您等待足够长的时间让您的应用程序变得空闲,您确实会恢复您的内存,即它并不是真正的泄漏。但是,正如您所观察到的,虽然 Visual C++ 2010 继续消耗越来越多的内存 - 直到在 OnIdle() 中整理地图 - 这似乎不会在 Visual C++ 2008 中发生。

调试包含您的代码的应用程序确实表明,VC 10 版本中的 HWND 临时映射中的对象比 VC 9 版本中的对象多得多。

两个版本之间的句柄映射代码 (winhand.cpp) 似乎没有变化,但 MFC 中有很多代码使用它!

无论如何,假设你真的想像这样运行你的程序——我猜你是在某种自动化模式下运行?- 然后你会想要在适当的时间间隔强制垃圾收集。看看 MSDN 上的这个条目:

http://msdn.microsoft.com/en-us/library/xt4cxa4e(v=VS.100).aspx

CWinThread::OnIdle() 实际上调用它来整理东西:

AfxLockTempMaps();
AfxUnlockTempMaps(/*TRUE*/);
于 2011-08-19T09:41:23.190 回答