C++具有动态分配和释放内存的能力,所谓成也萧何败萧何,这种能力如果使用疏忽会造成内存泄露。本文简单介绍2种检测内存泄露的方法。
【使用调试器和CRT库】
在程序的开头包含如下说明。在VS2010平台上,如果要显示泄露的内存原先分配的地方,需要包括下面第二段(在VS2008上就不用),在调试模式下开启new的内存分配跟踪,显示文件和行号。
#include "stdafx.h"
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
在需要检测内存泄露的地方,包含_CrtDumpMemoryLeaks()。
int _tmain(int argc, _TCHAR* argv[])
{
int* pi = new int;
char* name = new char[4];
name[0] = 'L';
name[1] = 'i';
name[2] = 'l';
name[3] = 'y';
_CrtDumpMemoryLeaks();
delete pi;
return 0;
}
注意_CrtDumpMemoryLeaks只是显示当前的内存泄露,即它执行时,所有未销毁的对象均会被报告出来,所以应该尽量在程序的最后执行。上文中虽然指针 pi 被正确释放了,但是在_CrtDumpMemoryLeaks之后,所以output窗口的输出仍然会报告 pi 的泄露情况。
双击报告文件行号的那行,可以跳转到code中的相应位置。
{118}:第118次内存分配操作发生了泄露。在初始化过程中肯定已经分配过很多了,所以上文第一次分配是117次,第二次是118次。
block:内存的类型,本文都是normal block。常用的有三种:
-normal (普通):程序分配的内存。
-client (客户端):专门用于MFC程序中需要析构函数的对象。MFC new操作符根据具体情况,为所创建的对象建立普通块或者客户块。
-CRT(运行时):由C Runtime Library 供自己使用而分配的内存块,有CRT 库自己来管理。
0x00348998:以16进制表示的内存位置
4 bytes:以字节表示的内存块的大小。
Data:内存块中前16个字节的内容。
如果程序有多个出口,或者不确定在哪儿会退出,可以在程序的开头包含以下语句,那么无论程序在哪里退出,都会自动调用_CrtDumpMemoryLeaks
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
由于 pi 指针已经被成功释放了,所以这次报告的泄露只有name。
【使用工具】
我使用的工具叫做:BoundsChecker 7。仍以上文的代码为例,编译生成MemoryLeakTest.exe。
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
int* pi = new int;
char* name = new char[4];
name[0] = 'L';
name[1] = 'i';
name[2] = 'l';
name[3] = 'y';
return 0;
}
P.S. 得把刚才“使用调试器和CRT库”加的相关代码都去掉,不然检测不出来,不知道为啥。。
在BC中打开exe文件,Program -> Settings中可以设置命令行参数。“General”页面中,可以勾上“Show memory and resource viewer when application exits”,在“Memory Tracking”页面,也有相关设置。
执行完毕出现“BoundsChecker Memory and Resource Viewer”。列举出了内存泄露的具体信息。
其他工具还有(都没用过)等。
Visual Leak Detector:http://apps.hi.baidu.com/share/detail/1927208
puriify
【参考】