Windows平台下的内存泄露
使用CRTDBG
#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
int main()
{
char * p = new char[10];
_CrtMemDumpAllObjectsSince(nullptr); // or _CrtDumpMemoryLeaks();
return 0;
}
F5Debug输出内容为:
Dumping objects ->
d:\dev\csharptest\cpptest\main.cpp(262) : {236} client block at 0x00265C78, subtype 0, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
Object dump complete.
从上面的宏可以看出来,将new重新宏定义为 new( _CLIENT_BLOCK, __FILE__, __LINE__)这样就可以定位到出现泄露的分配代码行。
如果没有macro new则只是打印出有多少的内存泄露。
从这里我们将会详细讨论CRT Debug Heap来检查内存泄露。
首先CRT Debug只针对与托管代码,也就是C++。
使用CRTDGB,需要按照如下顺序引用头文件,否则将会产生失败。
#define _CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h>宏_CRTDBG_MAP_ALLOC的作用是编译期中使用了crtdbg.h的_malloc_dbg 与 free来代替原有的malloc与free,如果你不define这个宏,你将需要将使用new的地方显示调用_malloc_dbg函数。这样也说明只能在_DEBUG宏下使用这个已经转义的malloc与free。如果是release,则使用原有的malloc与free函数。由于crtdbg.h对_malloc_dbg进行重新定义,记录的分配内存的细节,大少,代码文件以及对应的行数。
void *_malloc_dbg(
size_t size,
int blockType,
const char *filename,
int linenumber
);
通过函数的定义,size是由于new提供的(原有的new也是传递字节数给原有的malloc函数),后面的_CLIENT_BLOCK, __FILE__, __LINE__分别赋值于blockType, filename, linenumber。
_CrtDumpMemoryLeaks();
该函数将内存泄露信息打印到Debug面板中的Output窗口,同时该函数需要放置在程序退出前调用。如果程序中有很多异常处理导致可能程序退出的位置有很多,可以在程序入口出使用如下代码,它会在程序退出前自动调用_CrtDumpMemoryLeaks()函数。
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
如果需要打印详细的内存分配情况可以使用Statistics函数,同时可以定位到具体调用内存分配(我没有成功实现过。。。)
_CrtMemState s1, s2, s3;
char * _p = nullptr;
_CrtMemCheckpoint(&s1);
GetMemory(_p, 10);
_CrtMemCheckpoint(&s2);
if (_CrtMemDifference(&s3, &s1, &s2))
_CrtMemDumpStatistics(&s3);
建立3个信息对象,然后在分配内存操作的前后通过调用_CrtMemCheckpoint捕抓信息,接着使用_CrtMemDifference对比两者信息然后通过_CrtMemDumpStatistics打印信息。
使用Visual Leak Detector
下载visual leak detector并且安装
添加环境变量VLD并且在项目的头文件添加$(VLD)\include,在link搜索库中添加$(VLD)\lib\Win$(PlatformArchiteture)\
编译代码通过DEBUG运行程序,内存泄露信息将出现在DEBUGpanel的Output窗口中。
---------- Block 1 at 0x003B5328: 10 bytes ----------
Call Stack:
d:\dev\csharptest\cpptest\main.cpp (121): cpptest.exe!GetMemory + 0x9 bytes
d:\dev\csharptest\cpptest\main.cpp (262): cpptest.exe!main + 0xB bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (555): cpptest.exe!__tmainCRTStartup + 0x19 bytes
f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (371): cpptest.exe!mainCRTStartup
0x75B93677 (File and line number not available): kernel32.dll!BaseThreadInitThunk + 0x12 bytes
0x77069F42 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x63 bytes
0x77069F15 (File and line number not available): ntdll.dll!RtlInitializeExceptionChain + 0x36 bytes
Data:
CD CD CD CD CD CD CD CD CD CD ........ ........
通过上面可以看到使用vld的好处时使用简单,就是安装一个库,同时在代码中引用头文件而已,可以通过宏预编译来控制是否进行内存泄露检查。
Linux平台下内存泄露
待补