您的位置:首页 > 编程语言 > C语言/C++

C++中内存泄漏的检查与定位

2012-07-17 17:51 405 查看
本文仅仅是一些简短讲述一下,关于C++在Windows平台下内存泄漏内存泄漏的检查与定位。请参阅《最快速度找到内存泄漏》

在Windows平台下,可以借助头文件<crtdbg.h>中定义的一以下几个函数来完成。

_CrtDumpMemoryLeaks();
// 置于main函数最后,打印内存泄露报告

_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
// 置于main函数开头(当当前程序没有统一退出点时)

long _CrtSetBreakAlloc(long lBreakAlloc);
//用于在给定内存分配操作时停止当前程序


以下是_CrtDumpMemoryLeaks()的详细代码。(仅在Debug版本下有效)

#include <crtdbg.h>

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 <crtdbg.h>

#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 <crtdbg.h>

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)上测试有效,暂时未在其它情况下验证过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: