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

本文仅仅是一些简短讲述一下,关于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)上测试有效,暂时未在其它情况下验证过。

你可能感兴趣的:(C++)