一、_CrtDumpMemoryLeaks
C运行库的Debug版本提供了许多检测功能,使得我们更容易的Debug程序,我们会用到里面很重要的几个函数。其中最重要的是 _CrtDumpMemoryLeaks()。使用这个函数,需要包含头文件crtdbg.h。
该函数只在Debug版本才有用,当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在输出窗口中显示内存泄漏信息。
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
int main()
{
int *p = new int;
_CrtDumpMemoryLeaks();
return 0;
}
原理
在使用Debug版的malloc分配内存时,malloc会在内存块的头中记录分配该内存的文件名及行号。当程序退出时CRT会在main()函数返回之后做一些清理工作,这个时候来检查调试堆内存,如果仍然有内存没有被释放,则一定是存在内存泄漏。从这些没有被释放的内存块的头中,就可以获得文件名及行号。
缺点
只能检测出内存泄漏及其泄漏点的文件名和行号,但是并不知道泄漏究竟是如何发生的、该内存分配语句是如何被执行到的。
二、Visual Leak Detector
Visual Leak Detector是一款用于Visual C++的免费的内存泄露检测工具。
相比较其它的内存泄露检测工具,它在检测到内存泄漏的同时,还具有如下特点:
1、 可以得到内存泄漏点的调用堆栈,如果可以的话,还可以得到其所在文件及行号;
2、 可以得到泄露内存的完整数据;
3、 可以设置内存泄露报告的级别;
4、 它是一个已经打包的lib,使用时无须编译它的源代码。而对于使用者自己的代码,也只需要做很小的改动;
5、 他的源代码使用GNU许可发布,并有详尽的文档及注释。对于想深入了解堆内存管理的读者,是一个不错的选择。
原理
在这之前,我们先来看一下_CrtDumpMemoryLeaks是如何工作的。在使用Debug版的malloc分配内存时,malloc会在内存块的头中记录分配该内存的文件名及行号。CRT会在_CrtDumpMemoryLeaks函数调用的时候来检查调试堆内存,如果仍然有内存没有被释放,则一定是存在内存泄漏。从这些没有被释放的内存块的头中,就可以获得文件名及行号。
这种静态的方法可以检测出内存泄漏及其泄漏点的文件名和行号,但是并不知道泄漏究竟是如何发生的,并不知道该内存分配语句是如何被执行到的。要想了解这些,就必须要对程序的内存分配过程进行动态跟踪。Visual Leak Detector就是这样做的。它在每次内存分配时将其上下文记录下来,当程序退出时,对于检测到的内存泄漏,查找其记录下来的上下文信息,并将其转换成报告输出。
三、tMemMonitor (TMM)
Tencent tMem Monitor是腾讯推出的一款运行时C/C++内存泄漏检测工具。TMM认为在进程退出时,堆内存中没有被释放且没有指针指向的无主内存块即为内存泄漏,并进而引入垃圾回收(GC, Garbage Collection)机制,在进程退出时检测出堆内存中所有没有被引用的内存单元,因而内存泄露检测准确率为100%(官方说明)。不过我自己在使用这些工具和方法的过程中,发现TTM的内存泄漏检测准确率是上述所有方法中最高的,特别程序中使用了libxml2库使用不正确导致的内存泄漏也能检测出来。
但是TTM也有个小缺点,它并不适用于检测小程序。
TMM工具主要包含两部分,第一部分是客户端的检测界面,客户端部分主要负责监控目标进程中的内存行为并计算内存泄漏。检测时只要将被检测程序添加到监控列表中,然后正常运行被检程序即可。