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平台下内存泄露
待补