一般来说,当一个应用进程存在存在内存泄漏的时候,可采用微软推荐的标准方法来进行检查。
当然,这个方法只适用于运行期库的标准堆,进程创建的私有堆不能用此方法来检测,这种情况我们暂时不考虑。
先大概说一下微软推荐的检测方法。
检测内存泄漏的主要工具是调试器和 C 运行时库 (CRT) 调试堆函数。若要启用调试堆函数,请在程序中包括以下语句:
#define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h>
通过包括 crtdbg.h,将 malloc 和 free 函数映射到其“Debug”版本 _malloc_dbg 和 _free_dbg,这些函数将跟踪内存分配和释放。此映射只在调试版本(在其中定义了 _DEBUG)中发生。发布版本使用普通的 malloc 和 free 函数。
#define 语句将 CRT 堆函数的基版本映射到对应的“Debug”版本。并非绝对需要该语句,但如果没有该语句,内存泄漏转储包含的有用信息将较少。
在添加了上面所示语句之后,可以通过在程序中包括以下语句来转储内存泄漏信息:
_CrtDumpMemoryLeaks();
这样,在调试输出区就能看到堆泄漏检测的内容了,而且里面还包含了源代码信息,极大的方便了调试工作。
微软又提到:
如果程序总是在同一位置退出,调用 _CrtDumpMemoryLeaks 将非常容易。如果程序从多个位置退出,则无需在每个可能退出的位置放置对 _CrtDumpMemoryLeaks 的调用,而可以在程序开始处包含以下调用:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
这样,只有在入口函数退出之后,运行期库进行最后的清理工作结束之前,_CrtDumpMemoryLeaks才会被真正调用,你将有机会把自己创建的全局对象所占用的内存释放掉,避免这些内存被统计到未释放的堆当中。
需要注意的是,前面的头文件包含应该被源代码中的每个模块所引用,未引用的模块的堆信息在输出的时候将无法被识别,所以你最好将这个头文件包含放在类似afxstd.h的预包含文件中,以保证所有模块都能引用到这组头文件信息。
另外 ,可以把输出信息重定向到比如磁盘的文件中,方法是调用这个函数:_CrtSetReportMode。
现在再介绍在实际应用中发现的问题,上面的步骤可以解决你自己的程序的堆泄漏问题,但如果你的可执行程序引用了其他库,静态的或者是动态的,如果这些库中也存在堆泄漏,那么你是看不到源代码信息的,只能看到原始信息!
下面只说静态库且有源代码的情况,这时候,你可以在这个静态库的源代码的每个模块中加入上面提到的语句:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
这样,你在调试输出中就能看到源代码信息了,至于动态库的问题在后续中再分析。