本文仅仅是一些简短讲述一下,关于C++在Windows平台下内存泄漏内存泄漏的检查与定位。请参阅《最快速度找到内存泄漏》。
在Windows平台下,可以借助头文件
_CrtDumpMemoryLeaks();
// 置于main函数最后,打印内存泄露报告
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
// 置于main函数开头(当当前程序没有统一退出点时)
long _CrtSetBreakAlloc(long lBreakAlloc);
//用于在给定内存分配操作时停止当前程序
以下是_CrtDumpMemoryLeaks()的详细代码。(仅在Debug版本下有效)
#include
void main()
{
int* pLeak = new int[10];
pLeak = nullptr;
_CrtDumpMemoryLeaks();
}
这样在当前程序执行结束后,在Vistual Studio的Output窗口中会输出如下信息:
Detected memory leaks!
Dumping objects ->
c:/work/test.cpp(186) : {52} normal block at 0x003C4410, 40 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
以上信息似乎仅仅告诉了我们内存泄漏发生了,但依旧难以定为具体的内存泄漏的位置。
以下是改进后的版本:
#define _CRTDBG_MAP_ALLOC
// 用于将malloc和free函数重定向至DEBUG版本,使之能输出对应的源文件及行号。
#include
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
// 重定向new关键字,否则对于所有的new操作,依旧无法正确输出对应的源文件及行号。
void main()
{
int* pLeak = new int[10];
pLeak = nullptr;
_CrtDumpMemoryLeaks();
}
但有些时候,这依旧很难帮助我们找到具体的内存泄漏点。
我们注意到,在以上内存泄漏报告中有一个奇怪的信息({52}),其表示是第52次内存分配时,所分配的内存未被回收。
方法long _CrtSetBreakAlloc(long lBreakAlloc)可以使程序停止在指定的内存分配操作处(即:第52次内存分配)。
#include
void main()
{
_CrtSetBreakAlloc(52);
int* pLeak = new int[10];
pLeak = nullptr;
_CrtDumpMemoryLeaks();
}
再次在VS中执行上述代码,程序会在指定处停止并进入调试状态。通过查看函数调用堆栈,便可以精确定位出错的代码行,及当时的程序运行状态。
在这里,还有一点要注意的是C++的全局变量,一些全局变量的初始化会在进入main方法前就发生了。这种情况下,上述方法依旧无效。详见下例:
struct MyCls
{
string SubExprStr;
};
MyCls g_MyCls = {
string("Hello world!")
};
上述代码中,g_MyCls对象实例的初始化在进入main方法前就完成了。在这种情况下,可以通过设置条件断点来完成。具体如下:
// file 'dbgheap.c'
extern "C" static void * __cdecl _heap_alloc_dbg_impl(
size_t nSize,
int nBlockUse,
const char * szFileName,
int nLine,
int * errno_tmp
)
{
// ...
/* lock the heap
*/
_mlock(_HEAP_LOCK);
__try {
// ...
/* break into debugger at specific memory allocation */
if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)
_CrtDbgBreak();
在以下行处设置条件断点,在变量lRequest等于给定内存分配次数时停止执行。
if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)
上述方法在本人的机器(Windows 7 VS2010)上测试有效,暂时未在其它情况下验证过。