我想在Windows中检测我的C ++程序的内存泄漏。 我在MSDN上也阅读了有关 mermoy leak detection 的文档,我也开始使用Visual Leak Detector。
我对泄漏的报告存有疑问。 我期待一个带行号的文件名,但我总是报告下面的文字。 它包含泄漏描述的所有组件(块类型,内存地址,数据等)。 除文件名和行号外。
如果是真正的泄漏? 如果是,您知道为什么不报告文件/行吗? 与此同时,我也在this url
看一看由于
Detected memory leaks! Dumping objects -> {4723} normal block at 0x04AFB5B8, 8 bytes long. Data: 2C 3F 00 00 28 3F 00 00 {1476} normal block at 0x04AC3B58, 12 bytes long. Data: 00 CD CD CD EB 01 75 4C CA 3D 0B 00 Object dump complete.
答案 0 :(得分:7)
我研究了很多跟踪内存泄漏的方法。他们都有自己的优势,但也有缺点。
要了解它们的优缺点,我们必须了解不同的机制和要求:
如何拦截new,delete,malloc和free?有些工具使用#define来重新定义new,delete,malloc和free,但是这依赖于包含文件的正确顺序,并且如果类包含例如,则可能会出现问题。一个名为free的方法(如Qt中的情况)。预处理器还将重新定义此方法,这可能导致编译错误或未解析的外部。
另一种方法是否决全局new和delete运算符。这是一个更清洁的解决方案,但失败的是你有一个第三方库,它在库中放置一个新的,但在标题中删除(反之亦然)。
如何确定通话来源。如果使用#define截取new,delete,...,通常使用预处理程序符号__FILE__
和__LINE__
来获取泄漏源。但是,如果您的代码中包含“通用”功能,例如CreateString(),然后大多数泄漏将在这些通用函数中报告,这对您没有实际帮助。
另一种方法是在运行时获取调用堆栈。使用Windows StackWalk功能可以很容易地完成,但根据我的经验,这非常非常慢。更快的替代方法是直接获取基指针,并依赖堆栈帧指针(必须使用/ Oy-编译才能获得堆栈帧指针)。您可以像这样获取帧(基础)指针:_asm mov DWORD PTR [FramePtr], ebp
。然后简单地循环并在循环中获取来自((ADDR *)FramePtr)[1];
的指令指针和来自FramePtr = ((ADDR *)FramePtr)[0];
的下一个帧指针
如何准确报告泄漏情况。在我的情况下,我希望在应用程序结束时报告泄漏,但是为了能够执行此操作,您需要在应用程序结束时使用泄漏报告机制。这意味着如果您想自己报告泄漏,则需要依赖于在应用程序结束时被破坏的全局变量(并报告全局变量的析构函数中的泄漏)。对于服务器类型的应用程序,您可能更感兴趣的是在两个时间点之间获得内存使用量的差异。
现在不同的泄漏系统:
C RunTime:报告最后的泄漏,但没有报告调用堆栈的好方法。它拦截对new,delete,...的调用的方法可能会导致与第三方库(如Qt,Boost,...)组合出现问题
外部Microsoft实用程序(如GFlags,UMDH,......):他们似乎只能记录两个时间点之间的差异。但是,调用堆栈似乎要好得多,尽管GFlags实用程序可能会在操作系统中设置可能导致应用程序严重减速的标记。
视觉检漏仪。似乎正确找到所有泄漏,但在我的情况下,它不起作用,因为我有一个第三方DLL只是在其DllUnload中中止进程(似乎是Windows 7特定的问题)。
我个人的最爱(人们不会同意我,我敢肯定),就是写自己的记忆管理员。使用全局new和delete运算符(可能存在上述问题)可以轻松完成拦截,并且可以按上述方法获取调用堆栈。这种替代方案还依赖于能够在应用程序的最后一刻执行代码。
在选择替代方案时,我发现以下几个方面对我的情况非常重要:
希望这有帮助。
答案 1 :(得分:5)
这是Visual Studio自己的调试CRT的输出,而不是Visual Leak Detector的输出。首先确保您在Codeplex使用当前版本,并在项目中使用#included vld.h。您将获得更多信息。
答案 2 :(得分:2)
我在调试了很多头文件后得到了它。
以下是在输出中启用文件/行号所必须做的事情
#define _CRTDBG_MAP_ALLOC
#define _CRTDBG_MAP_ALLOC_NEW
答案 3 :(得分:1)
您是否在启用调试信息的情况下编译并确保泄漏检测器可以使用pdb文件?没有这些信息,它将无法提供行号。
答案 4 :(得分:0)
你应该使用Valgrind,这是非常强大的,并正确解释你的程序中的泄漏位置。您的程序可能需要使用gcc编译,但是......
答案 5 :(得分:0)
Rational Purify可用作VC ++的for-money插件,是一个非常好的泄漏(和其他麻烦)探测器。我以前在Solaris上经常使用它,而且非常易于使用和清除。我也从其他人那里听说过与Visual Studio一起使用的版本的好东西,但我从来没有尝试过。
FWIW,我怀疑Purify是Valgrind的灵感,已经提到过。
答案 6 :(得分:0)
如果分配编号(卷曲括号中的编号)始终相同,this could help。基本上,它描述了在尝试使用指定数量的分配时如何使VC ++生成断点。