C++下面的内存泄露检测

内存的管理机制是写代码过程中一个比较重要的功能模块,因为内存泄露是很难调试出来的,会给软件埋下定时炸弹。在C++

环境下有相关的内存检测的方式,这里简单的罗列一下,避免以后自己会忘记,基本上是参考网络上面一篇文章:

在VC下面有这样的一个头文件crtdbg.h,专门用于内存的管理。

我们会用到里面很重要的几个函数。其中最重要的是 _CrtDumpMemoryLeaks();自己看MSDN里的帮助吧。使用这个函数,需要包含头文件crtdbg.h
该函数只在Debug版本才有用,当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“Output(输出)”窗口中显示内存泄漏信息.写段代码试验一下吧,如下:

 

#include "stdafx.h"
#include <crtdbg.h>

int _tmain(int argc, _TCHAR* argv[])
{
   int* p = new int();
     _CrtDumpMemoryLeaks();
     return 0;
}

注意这个函数只有debug条件下才会有作用,并且答应的信息输出在vc下面的output窗口中。

Detected memory leaks!
Dumping objects ->
{104} normal block at 0x00697870, 4 bytes long.
 Data: <    > 00 00 00 00
Object dump complete.
The program '[4688] MemDebug.exe: Native' has exited with code 0 (0x0).

 

但是这个函数还是很郁闷,我们不知道内存泄露在什么地方,于是我们有了内存泄露的第二个版本。

在引入这个头文件之前,假如这样的宏

#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
#endif

#include <crtdbg.h>

 

int _tmain(int argc, _TCHAR* argv[])
{
   int* p = new int();
     _CrtDumpMemoryLeaks();
     return 0;
}

 

我们会发现现在的打印信息为

Detected memory leaks!
Dumping objects ->
i:/vc_test/memdebug/memdebug/memdebug.cpp(21) : {104} client block at 0x003B7870, subtype 0, 4 bytes long.
 Data: <    > 00 00 00 00
Object dump complete.
The program '[3064] MemDebug.exe: Native' has exited with code 0 (0x0).

 

这样就包含了泄露内存最开始分配的时候的地址。

 

该程序定义了几个宏,通过宏将Debug版本下的new给替换了,新的new记录下了调用new时的文件名和代码行.

但是这个还不是最终版本,我们可以这样的代码来测试:

int _tmain(int argc, _TCHAR* argv[])
{
   int* p = new int();
     _CrtDumpMemoryLeaks();
     delete p;
     return 0;
}
发现我们释放掉的时候,还是有提示说内存错误,这个就有问题了。

运行后可以发现我们删除了指针,但是它仍然报内存泄露。所以可以想象,每调用一次new,程序内部都会将该调用记录

下来,类似于有个数组记录,假如delete了,那么就将其从数组中删除,而_CrtDumpMemoryLeaks()就是把这个数组

当前的状态打印出来。所以除了在必要的时候Dump出内存信息外,最重要的就是在程序退出的时候需要掉用一次_CrtDumpMemoryLeaks();
 假如程序有不止一个出口,那么我们就需要在多个地方都调用该函数。

这个就是说,我们把debug模式下的new改变了一下,这个时候每一次new都会忘某个调试分配的表中添加一条信息,如果

delete,这个信息就会删掉,我们只能在程序最终退出的地方加上这样的一个函数CrtDumpMemoryLeaks表示需要打印

内存泄露。程序改成这样就会没有:

int _tmain(int argc, _TCHAR* argv[])
{
   int* p = new int();
    
     delete p;
     _CrtDumpMemoryLeaks();
     return 0;
}
根据这个原理我们可以推断出下面的程序也会出现内存泄露的错误:

class Test
{
public:
    Test()      {   _p = new int();     }
    ~Test()     {   delete _p;          }
    int* _p;
};

int _tmain(int argc, _TCHAR* argv[])
{
   int* p = new int();
     delete p;
     Test t;
     _CrtDumpMemoryLeaks();
     return 0;
}

造成这个的原因就是我们没有保证这个函数是在程序最后调用的,因为Test t是一个局部类,在程序退出的时候,程序会自动

的调用析构,这个调用析构在CrtDumpMemoryLeaks之前,所以就会有这样的问题,如何来改进呢?如何保证我们的这个CrtDumpMemoryLeaks的调用一定在程序的最后,这个在我们自己的代码中是无法做到的,因为C++的析构是编译器的

特性,析构的调用是编译器自己调用的。

 

但是我们有这样的一个宏,让编译器知道程序退出的时候调用我们这个函数:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

代码如下:


class Test
{
public:
    Test()      {   _p = new int();     }
    ~Test()     {   delete _p;          }
    int* _p;
};

int _tmain(int argc, _TCHAR* argv[])
{
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
   int* p = new int();
     delete p;
     Test t;
     return 0;
}

但是我觉得光这样还不够,因为我们只是在Output窗口中输出信息,对开发人员的提醒还不明显,经常会被遗漏,而且很

多人就算发现了内存泄露,但是不好 修复,不会严重影响到程序外在表现,都不会修复。怎么样能让开发人员主动的修

复内存泄露的问题呢?记得曾经和人配合写程序,我的函数参数有要求,不能为 空,但是别人老是传空值,没办法了,

只好在函数开始验证函数参数,给他assert住,这样程序运行时老是不停的弹出assert,调试程序那个烦压,最 后其他程

序员烦了,就把这个问题给改好了,输入参数就正确了。所以我觉得咱要让程序员主动去做一件事,首先要让他觉得做这个

事是能减轻自己负担,让自己工 作轻松的。呵呵,那咱们也这样,当程序退出时,检测到内存泄露就让程序提示出来。

代码如下:

#include "stdafx.h"

#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
#endif

#include <crtdbg.h>
#include <assert.h>


class Test
{
public:
    Test()      {   _p = new int();     }
    ~Test()     {           }
    int* _p;
};

 void Exit()
 {
     int i = _CrtDumpMemoryLeaks();
     assert( i == 0);
 }
int _tmain(int argc, _TCHAR* argv[])
{

     atexit(Exit);
   int* p = new int();
     delete p;
     Test t;
     return 0;
}

运行起来果然发现,Test析构的时候没有释放掉内存,现在终于知道xp下面经常弹出来的那个终止忽略调试对话框是如何

出来的。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值