C++项目总结一之内存泄漏检测

在编写C++程序时避免不了要通过malloc/new/realloc来分配堆中的内存;堆中的内存使用完成后由程序员进行释放归还给操作系统。如果动态动态分配的内存没有释放,就会造成内存泄漏。vc提供的运行时函数_CrtDumpMemoryLeaks用于检测在堆中分配的内存没有释放时转储所有泄漏的内存块信息。
程序1:内存泄漏展示

#include <windows.h>
#include <stdio.h>
#include <crtdbg.h>
int main()
{
    int *p = (int*)malloc(sizeof(int));
    _CrtDumpMemoryLeaks();
    return 0;
}

在vs2008的输出窗口,我们看到内存泄漏提示
这里写图片描述

从图中可以看到共有4字节的内存泄漏。但是从上面中只能看到有4字节的泄漏,如果能够有更多的信息比较提示内存泄漏发生在哪个文件,哪一行就更容易定位问题了。vs2008自带的有一个crtdbg.h的文件,里面有对malloc的重定义;但对malloc的重定义是根据是否定义了_CRTDBG_MAP_ALLOC宏,如果定义的该宏就会重定义malloc,重定义后的malloc会记录分配时的文件名及所在行。

程序2:显示内存泄漏所在行

#include <windows.h>
#include <stdio.h>
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>

int main()
{
    int *p = (int*)malloc(sizeof(int));
    _CrtDumpMemoryLeaks();
    return 0;
}

输出窗口信息:
这里写图片描述
到此可以看到在source.cpp的第8行出现了内存泄漏,泄漏4字节。
在上面的程序2中,如果free(p)在_CrtDumpMemoryLeaks()之后,程序运行后仍然会提示内存泄漏。如果定义了全局对象,全局对象是在main运行之后才进行析构函数调用。这样在main函数中调用_CrtDumpMemoryLeaks()还是会检测到内存泄漏,下面看程序3。
程序3:

#include <windows.h>
#include <stdio.h>
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
class A
{
public:
    A(){p = (int*)malloc(sizeof(int));}
    ~A(){delete p;}
private:
    int *p;
};
A obj;
int main()
{
    _CrtDumpMemoryLeaks();
    return 0;
}

运行上面的程序后,vs2008输出窗口如下:
这里写图片描述
可以看到输出窗口提示程序第8行发生了内存泄漏,实际情况是并没有发生内存泄漏。下面来看另外一个函数_CrtSetDbgFlag,使用这函数通过设置_CRTDBG_ALLOC_MEM_DF及_CRTDBG_LEAK_CHECK_DF,可以在程序退出的时候转储泄漏的内存块。
程序4:

#include <windows.h>
#include <stdio.h>
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
class A
{
public:
    A(){p = (int*)malloc(sizeof(int));}
    ~A(){delete p;}
private:
    int *p;
};
A obj;
int main()
{
    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
    int *p = (int*)malloc(sizeof(int));
    return 0;
}

程序运行后输出如下信息:
这里写图片描述
输出窗口显示我们的程序第17行存在没释放的堆内存,而全局对象中则不存在没释放的内存。这个提示的内存泄漏信息就是正确的。而不会误报全局对象的中的内存没有释放。
上面对malloc分配的内存是否泄漏进行了检测,但是对于C++的new进行分配的内存还没有检测。MSDN中有一段对于new运算符进行宏替换的代码:

#ifdef _DEBUG
   #define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
   #define DEBUG_CLIENTBLOCK
#endif
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

程序5:

#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
class A
{
public:
    A(){p = (int*)malloc(sizeof(int));}
    ~A(){delete p;}
private:
    int *p;
};
A obj;
int main()
{
    _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
    int *p = new int;
    return 0;
}

程序运行后vs2008窗口输出信息:
这里写图片描述
到此我们程序中,即可以检测出malloc也可以检测出new分配的没释放的内存。
在实际项目中我们发现,上面用于检测内存泄漏所定义的宏几乎每个cpp文件中都需要,不然就有可能无法检测出内存泄漏。这样把上面的预处理代码放到一个头文件中,这样只需要在每个cpp文件中包含这个头文件就可以了。假设这个头文件名为:common.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

在cpp文件中最好将#include”common.h”放到所#include指令的最后一个;以防后面包含的头文件会对malloc、free、new、delete进行重新定义。

本文参考:
浅谈C++中内存泄漏的检测

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值