如何忽略_CrtDumpMemoryLeaks中的误报内存泄漏?

15

似乎每当存在静态对象时,_CrtDumpMemoryLeaks 函数都会返回一个错误的结果,声称内存泄漏。我知道这是因为它们直到 main() 或 WinMain 函数执行完毕才被销毁。但有没有什么方法可以避免这种情况?我使用的是VS2008。

7个回答

14

我发现如果在程序终止后告诉它自动检查内存,它就可以将所有静态对象计算在内。我正在使用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 库的代码中仍然存在内存泄漏问题BOOST_LOG_TRIVIAL(error) << "Module: ";设置 _CrtSetDbgFlag 也没有起到帮助作用。您有任何想法吗? - Pritesh Acharya

3
并非直接解决方案,但总的来说,我发现尽可能将大部分分配从静态初始化时间中移出是值得的。这通常会导致一些麻烦(初始化顺序、去初始化顺序等)。
如果这太难了,你可以在 main() 函数开始时调用 _CrtMemCheckpointhttp://msdn.microsoft.com/en-us/library/h3z85t43%28VS.80%29.aspx),并在结束时调用 _CrtMemDumpAllObjectsSince

1

虽然这是一个旧问题,但我有一个答案。我能够将报告分为假阳性和真正的内存泄漏。在我的主函数中,我初始化了内存调试并在应用程序的最开始生成了一个真正的内存泄漏(从不删除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.

现在看一下 "Data: <DynamicHeapStart> 44 79 6E 61 6D 69 63 48 65 61 70 53 74 61 72 74" 这一行。

以下所有报告的泄漏都是误报,以上所有泄漏都是真正的泄漏。 误报并不意味着没有泄漏(可能是静态链接库在启动时分配堆内存并且从不释放),但你无法排除泄漏,这并没有问题。

自从我发明了这种方法后,我的应用程序再也没有泄漏过。 我在这里提供它,希望这有助于其他开发人员获得稳定的应用程序。


由于您的类在静态初始化程序中使用可能会导致泄漏,这些泄漏也可能会在“DynamicHeapStart”行以下报告,即可能被错误地标记为假阳性。如果代码或链接模块的顺序发生更改,则它们的相对位置可能会发生变化。 - Frank Heimes

1

1) 你说:

似乎每当有静态对象时,_CrtDumpMemoryLeaks都会返回一个错误的正面结果,声称它正在泄漏内存。

我认为这是不正确的。编辑:静态对象不是在堆上创建的。结束编辑:_CrtDumpMemoryLeaks仅涵盖crt堆内存。因此,这些对象不应该返回错误的正面结果。 但是,如果静态变量是对象,它们本身持有一些堆内存(例如,如果它们使用operator new()动态创建成员对象),那就是另一回事了。

2) 考虑使用_CRTDBG_LEAK_CHECK_DF以在程序执行结束时激活内存泄漏检查(在此处描述:http://msdn.microsoft.com/en-us/library/d41t22sb(VS.80).aspx)。我想这样做后,即使在静态变量终止后也会进行内存泄漏检查。


静态对象不会分配在堆栈上。 - Billy ONeal
@Billy:感谢你的纠正...我想你是对的。然而,它们也不是在堆上分配的,对吗? - Stefan Hubert
1
我希望现在你们已经弄清楚了静态对象存储在哪里。 - Krum

0
我可以推荐使用免费的Visual Leak Detector,而不是使用VS内置的工具。我的问题是在使用_CrtDumpMemoryLeaks时,它会输出990行来自开源库的假阳性信息,以及一些来自boost的东西。VLD忽略了这些信息,并正确地报告了我添加用于测试的一些泄漏,包括从C#调用的本地DLL中的泄漏。

0

每次需要列表时,您能否拍摄当前分配的对象快照?如果可以,当您寻找操作中发生的泄漏时,可以从列表中删除最初分配的对象。过去,我曾使用此方法查找增量泄漏。

另一个解决方案可能是对泄漏进行排序,并仅考虑相同代码行的重复项。这应该排除静态变量泄漏。

Jacob


0
啊。如果你确定 _CrtDumpMemoryLeaks() 在撒谎,那么你可能是正确的。我看到的大多数所谓的内存泄漏都是由于对 _CrtDumpMemoryLeaks() 的不正确调用引起的。我完全同意以下观点;_CrtDumpMemoryLeaks() 转储所有打开的句柄。但是你的程序可能已经有了打开的句柄,所以请确保只在所有句柄释放后调用 _CrtDumpMemoryLeaks()。请参阅 http://www.scottleckie.com/2010/08/_crtdumpmemoryleaks-and-related-fun/ 以获取更多信息。

1
链接已失效。此外,_CrtDumpMemoryLeaks 不监视句柄。它严格参考调试堆中的内存块。 - IInspectable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接