【发布时间】:2011-01-20 09:00:44
【问题描述】:
似乎只要有静态对象,_CrtDumpMemoryLeaks 就会返回误报,声称它正在泄漏内存。我知道这是因为它们直到 main()(或 WinMain)函数之后才被销毁。但是有什么办法可以避免这种情况吗?我用的是VS2008。
【问题讨论】:
标签: c++ memory static memory-leaks
似乎只要有静态对象,_CrtDumpMemoryLeaks 就会返回误报,声称它正在泄漏内存。我知道这是因为它们直到 main()(或 WinMain)函数之后才被销毁。但是有什么办法可以避免这种情况吗?我用的是VS2008。
【问题讨论】:
标签: c++ memory static memory-leaks
我发现如果你告诉它在程序终止后自动检查内存,它允许所有的静态对象都被计算在内。我正在使用 log4cxx 和 boost 在静态块中进行大量分配,这修复了我的“误报”...
在 main() 开头的某处添加以下行,而不是调用 _CrtDumpMemoryLeaks:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
有关用法和宏的更多详细信息,请参阅 MSDN 文章:
http://msdn.microsoft.com/en-us/library/5at7yxcs(v=vs.71).aspx
【讨论】:
BOOST_LOG_TRIVIAL(error) << "Module: "; 设置 _CrtSetDbgFlag 的代码上出现内存泄漏并没有帮助。你有什么想法吗?
不是直接的解决方案,但总的来说,我发现将尽可能多的分配移出静态初始化时间是值得的。它通常会导致头痛(初始化顺序、反初始化顺序等)。
如果这太难了,您可以在main() 和_CrtMemDumpAllObjectsSince 的开头致电_CrtMemCheckpoint (http://msdn.microsoft.com/en-us/library/h3z85t43%28VS.80%29.aspx)
最后。
【讨论】:
1) 你说:
似乎只要有静态对象,_CrtDumpMemoryLeaks 就会返回一个误报,声称它正在泄漏内存。
我不认为这是正确的。 编辑: 静态对象不在堆上创建。 结束编辑: _CrtDumpMemoryLeaks 仅涵盖 crt 堆内存。因此,这些对象不应该返回误报。
但是,如果静态变量是本身持有一些堆内存的对象(例如,如果它们动态地创建带有operator new() 的成员对象),那就另当别论了。
2) 考虑使用 _CRTDBG_LEAK_CHECK_DF 以在程序执行结束时激活内存泄漏检查(此处描述:http://msdn.microsoft.com/en-us/library/d41t22sb(VS.80).aspx)。我想即使在静态变量终止后也会进行内存泄漏检查。
【讨论】:
老问题,但我有一个答案。我能够将报告分为误报和真实内存泄漏。在我的 main 函数中,我初始化了内存调试并在我的应用程序真正开始时生成了一个真正的内存泄漏(永远不要删除 pcDynamicHeapStart):
int main()
{
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
char* pcDynamicHeapStart = new char[ 17u ];
strcpy_s( pcDynamicHeapStart, 17u, "DynamicHeapStart" );
...
我的申请完成后,报告包含
Detected memory leaks!
Dumping objects ->
{15554} normal block at 0x00000000009CB7C0, 80 bytes long.
Data: < > DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD
{14006} normal block at 0x00000000009CB360, 17 bytes long.
Data: <DynamicHeapStart> 44 79 6E 61 6D 69 63 48 65 61 70 53 74 61 72 74
{13998} normal block at 0x00000000009BF4B0, 32 bytes long.
Data: < ^ > E0 5E 9B 00 00 00 00 00 F0 7F 9C 00 00 00 00 00
{13997} normal block at 0x00000000009CA4B0, 8 bytes long.
Data: < > 14 00 00 00 00 00 00 00
{13982} normal block at 0x00000000009CB7C0, 16 bytes long.
Data: < @ > D0 DD D6 40 01 00 00 00 90 08 9C 00 00 00 00 00
...
Object dump complete.
现在查看“数据:DynamicHeapStart> 44 79 6E 61 6D 69 63 48 65 61 70 53 74 61 72 74”行。
以下所有报告泄漏均为误报,以上均为真实泄漏。 误报并不意味着没有泄漏(它可能是一个静态链接库,它在启动时分配堆并且从不释放它),但是您无法消除泄漏,这完全没有问题。
自从我发明了这种方法以来,我再也没有泄露过应用程序。 我在这里提供这个,希望这有助于其他开发人员获得稳定的应用程序。
【讨论】:
您能否在每次需要列表时对当前分配的对象进行快照?如果是这样,您可以在查找操作中发生的泄漏时从列表中删除最初分配的对象。过去,我用它来查找增量泄漏。
另一种解决方案可能是对泄漏进行排序,并且只考虑同一行代码的重复项。这应该排除静态变量泄漏。
雅各布
【讨论】:
啊。如果您确定_CrtDumpMemoryLeaks() 在撒谎,那么您可能是正确的。我看到的大多数所谓的内存泄漏都归结为对_CrtDumpMemoryLeaks() 的不正确调用。我完全同意以下内容; _CrtDumpMemoryLeaks() 转储所有打开的句柄。但是你的程序可能已经有打开的句柄,所以一定要在所有句柄都被释放后才调用_CrtDumpMemoryLeaks()。请参阅http://www.scottleckie.com/2010/08/_crtdumpmemoryleaks-and-related-fun/ 了解更多信息。
【讨论】:
_CrtDumpMemoryLeaks 不监视句柄。它严格指调试堆中的内存块。
我可以推荐 Visual Leak Detector(它是免费的),而不是使用 VS 内置的东西。我的问题是使用 _CrtDumpMemoryLeaks 和一个开源库,该库创建了 990 行输出,据我所知,所有的误报,以及一些来自 boost 的东西。 VLD 忽略了这些并正确报告了我为测试添加的一些泄漏,包括从 C# 调用的本机 DLL。
【讨论】: