方法一:
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
//在入口函数中包含 _CrtDumpMemoryLeaks();
//即可检测到内存泄露
//以如下测试函数为例:
int main()
{
char* pChars = new char[10];
_CrtDumpMemoryLeaks();
return 0;
}
运行程序会在Output窗口得到:
注意:
1.在VS2013下测试的时候,_CrtDumpMemoryLeaks();这句必须放在函数结束处,放在主函数入口处输出窗口不会输出内存泄露信息
2.{}中的数字指明这块内存是程序中总计第几个被申请的,这种方法没有行号和其他信息输出。我们可以定义:
#ifdef _DEBUG
#define New new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
//在入口函数中包含 _CrtDumpMemoryLeaks();
//即可检测到内存泄露
//以如下测试函数为例:
int main()
{
char* pChars = New char[10];
_CrtDumpMemoryLeaks();
return 0;
}
Output窗口得到:
方法二:
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
//在入口函数中包含 _CrtDumpMemoryLeaks();
//即可检测到内存泄露
//定义函数:
inline void EnableMemLeakCheck()
{
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}
//该函数可以放在主函数的任意位置,都能正确的触发内存泄露输出
//以如下测试函数为例:
int main()
{
EnableMemLeakCheck();
char* pChars = new char[10];
//_CrtDumpMemoryLeaks();
return 0;
}
方法三:直接定位指定内存块错误的代码行
在内存泄漏情况复杂的时候,可以用以下方法定位内存泄漏,这是通用的内存泄漏追踪方法中最有效的手段。
我们再回头看看crtdbg生成的内存泄漏报告:
除了产生该内存泄漏的内存分配语句所在的文件名、行号为,我们注意到有一个比较陌生的信息:{68}。这个整数值代表了什么意思呢?
其实,它代表了第几次内存分配操作。象这个例子,{68}代表了第68次内存分配操作发生了泄漏。你可能要说,我只new过一次,怎么会是第68次?这很容易理解,其他的内存申请操作在C的初始化过程调用的呗~~~)
有没有可能,我们让程序运行到第68次内存分配操作的时候,自动停下来,进入调试状态?所幸,crtdbg确实提供了这样的函数:即 long _CrtSetBreakAlloc(long nAllocID)。我们加上它:
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
int main()
{
_CrtSetBreakAlloc(68);
char* pChars = new char[10];
_CrtDumpMemoryLeaks();
return 0;
}
你发现,程序运行到 char* pChars = new char[10];一句时,自动停下来进入调试状态。细细体会一下,你可以发现,这种方式你获得的信息远比在程序退出时获得文件名及行号有价值得多。因为报告泄漏文件名及行号,你获得的只是静态的信息,然而_CrtSetBreakAlloc则是把整个现场恢复,你可以通过对函数调用栈分析(我发现很多人不习惯看函数调用栈,如果你属于这种情况,强烈推荐你去补上这一课,因为它太重要了)以及其他在线调试技巧,来分析产生内存泄漏的原因。通常情况下,这种分析方法可以在5分钟内找到肇事者。
附一个完整的代码:
#include "stdafx.h"
#include <iostream>
#include "wydxml.h"
//可以定位到发生内存泄露 所在的文件和具体那一行,用于检测 malloc 分配的内存
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
//把分配内存的信息保存下来,可以定位到那一行发生了内存泄露。用于检测 new 分配的内存
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
//有用
inline void EnableMemLeakCheck()
{
//该语句在程序退出时自动调用 _CrtDumpMemoryLeaks(),用于多个退出出口的情况.
//如果只有一个退出位置,可以在程序退出之前调用 _CrtDumpMemoryLeaks()
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
}
int _tmain(int argc, _TCHAR* argv[])
{
EnableMemLeakCheck();
//运行到 第 191 次 内存分配的时候停下来
//_CrtSetBreakAlloc(191);
char* p = new char[100];
char* p1 = new char[200];
char* p2 = (char*)malloc(600);
delete p;
getchar();
//_CrtDumpMemoryLeaks();//这个代码好像会输出额外多余的内存分配信息
return 0;
}