当前位置:  编程技术>c/c++/嵌入式

C++内存泄漏及检测工具详解

    来源: 互联网  发布时间:2014-10-21

    本文导语:  首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复。 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck,功能非常强大,相信做C++开发的人都离不开它。此外就...

首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复。

最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck,功能非常强大,相信做C++开发的人都离不开它。此外就是不使用任何工具,而是自己来实现对内存泄露的监控,分如下两种情况:

一. 在 MFC 中检测内存泄漏

假如是用MFC的程序的话,很简单。默认的就有内存泄露检测的功能。

我们用VS2005生成了一个MFC的对话框的程序,发现他可以自动的检测内存泄露.不用我们做任何特殊的操作. 仔细观察,发现在每个CPP文件中,都有下面的代码:

代码如下:

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

DEBUG_NEW 这个宏定义在afx.h文件中,就是它帮助我们定位内存泄漏。

在含有以上代码的cpp文件中分配内存后假如没有删除,那么停止程序的时候,VisualStudio的Output窗口就会显示如下的信息了:

Detected memory leaks!
Dumping objects ->
d:codemfctestmfctest.cpp(80) : {157} normal block at 0x003AF170, 4 bytes long.
 Data: < > 00 00 00 00
Object dump complete.

在Output窗口双击粗体字那一行,那么IDE就会打开该文件,定位到该行,很容易看出是哪出现了内存泄露。

二.检测纯C++的程序内存泄露

我试了下用VisualStudio建立的Win32 Console Application和Win32 Project项目,结果都不能检测出内存泄露。

下面一步一步来把程序的内存泄露检测的机制建立起来。

首先,我们需要知道C运行库的Debug版本提供了许多检测功能,使得我们更容易的Debug程序。在MSDN中有专门的章节讲这个,叫做Debug Routines,建议大家先看看里面的内容吧。

我们会用到里面很重要的几个函数。其中最重要的是 _CrtDumpMemoryLeaks();自己看MSDN里的帮助吧。使用这个函数,需要包含头文件crtdbg.h

该函数只在Debug版本才有用,当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在“Output(输出)”窗口中显示内存泄漏信息.写段代码试验一下吧,如下:

检测内存泄露版本一:

代码如下:

#include "stdafx.h"
#include
int _tmain(int argc, _TCHAR* argv[])
{
    int* p = new int();
    _CrtDumpMemoryLeaks();
    return 0;
}

运行后,在Output(输出)窗口,显示了如下的信息:

Detected memory leaks!
Dumping objects ->
{112} normal block at 0x003AA770, 4 bytes long.
 Data: 00 00 00 00
Object dump complete.

但是这个只是告诉我们程序有内存泄露,到底在哪泄露了一眼看不出来啊。

看我们的检测内存泄露版本二:

代码如下:

#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
int _tmain(int argc, _TCHAR* argv[])
{
    int* p = new int();
    _CrtDumpMemoryLeaks();
    return 0;
}

该程序定义了几个宏,通过宏将Debug版本下的new给替换了,新的new记录下了调用new时的文件名和代码行.运行后,可以看到如下的结果:

Detected memory leaks!
Dumping objects ->
d:codeconsoletestconsoletest.cpp(21) : {112} client block at 0x003A38B0, subtype 0, 4 bytes long.
 Data: 00 00 00 00
Object dump complete.

呵呵,已经和MFC程序的效果一样了,但是等一等。看下如下的代码吧:

代码如下:

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

运行后可以发现我们删除了指针,但是它仍然报内存泄露。所以可以想象,每调用一次new,程序内部都会将该调用记录下来,类似于有个数组记录,假如delete了,那么就将其从数组中删除,而_CrtDumpMemoryLeaks()就是把这个数组当前的状态打印出来。

所以除了在必要的时候Dump出内存信息外,最重要的就是在程序退出的时候需要掉用一次_CrtDumpMemoryLeaks();

假如程序有不止一个出口,那么我们就需要在多个地方都调用该函数。

更进一步,假如程序在类的析构函数里删除指针,怎么办?例如:

代码如下:

#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
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;
}

可以看到析构函数在程序退出的时候才调用,明明没有内存泄露,但是这样的写法还是报了。

如何改进呢,看检测内存泄露版本三:

代码如下:

#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
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;
}

 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );该语句在程序退出时自动调用 _CrtDumpMemoryLeaks。必须同时设置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF.

这样,该版本已经达到了MFC一样的效果了,但是我觉得光这样还不够,因为我们只是在Output窗口中输出信息,对开发人员的提醒还不明显,经常会被遗漏,而且很多人就算发现了内存泄露,但是不好修复,不会严重影响到程序外在表现,都不会修复。怎么样能让开发人员主动的修复内存泄露的问题呢?记得曾经和人配合写程序,我的函数参数有要求,不能为空,但是别人老是传空值,没办法了,只好在函数开始验证函数参数,给他assert住,这样程序运行时老是不停的弹出assert,调试程序那个烦压,最后其他程序员烦了,就把这个问题给改好了,输入参数就正确了。所以我觉得咱要让程序员主动去做一件事,首先要让他觉得做这个事是能减轻自己负担,让自己工作轻松的。呵呵,那咱们也这样,当程序退出时,检测到内存泄露就让程序提示出来。

看检测内存泄露版本四:

代码如下:

#include "stdafx.h"
#include
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
void Exit()
{
    int i = _CrtDumpMemoryLeaks();
    assert( i == 0);
}
int _tmain(int argc, _TCHAR* argv[])
{
    atexit(Exit);
    int* p = new int();
    return 0;
}

该版本会在程序退出时检查内存泄露,假如存在就会弹出提示对话框.

atexit(Exit);设置了在程序退出时执行Exit()函数。Exit()函数中,假如存在内存泄露,_CrtDumpMemoryLeaks()会返回非0值,就会被assert住了。

到这个版本已经达到可以使用的程度了。但是我们还可以做些改进,因为真要准确的检测到代码中所有的内存泄露,需要把代码中的#define……拷贝到所有使用new的文件中。不可能每个文件都拷贝这么多代码,所以我们可以将他提取出来,放在一个文件中,比如我是放在KDetectMemoryLeak.h中,该文件内容如下:

代码如下:

#pragma once
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

然后将KDetectMemoryLeak.h包含在项目的通用文件中,例如用VS建的项目就将其包含在stdafx.h中。或者我自己建的一个Common.h文件中,该文件包含一些通用的,基本所有文件都会用到的代码。

    
 
 

您可能感兴趣的文章:

  • C++ Vectors 成员 get_allocator():返回vector的内存分配器
  • C++里能不能在指定的一块内存中创建对象的实例?
  • C++ Vectors 成员 capacity():返回vector所能容纳的元素数量(在不重新分配内存的情况下)
  • 内存外部计算的C++标准库 STXXL
  • tcmalloc内存泄露优化c++开源库下载,安装及使用介绍
  • C++内存管理库 Generic Memory Manager
  • C++程序的内存不同的数据段及堆栈布局
  • 请教一个linux c++调试问题(关于内存泄露)
  • 请教:在solaris下测试C++程序是否存在内存泄漏等问题用什么测试工具?
  • linux下c++对长度不定的字符串要进行预先动态分配内存需要怎么做?
  • C++中给二维指针分配内存(实现代码)
  • linux下C++动态malloc申请内存出现问题,高人指点一下,在线
  • 基于C++执行内存memcpy效率测试的分析
  • c++动态内存空间示例(自定义空间类型大小和空间长度)
  • 基于C++中常见内存错误的总结
  • C++内存查找实例
  • 深入解析C++ Data Member内存布局
  • 基于C++内存分配、函数调用与返回值的深入分析
  • c++实现逐行读取配置文件写入内存的示例
  • C++中关于Crt的内存泄漏检测的分析介绍
  • C语言、C++内存对齐问题详解
  • 内存泄漏是什么?怎么造成的?java中会不会产生内存泄漏?
  • 内存泄漏问题
  • 讨论“内存泄漏”
  • AIX下程序内存泄漏
  • Java 中如何检测内存泄漏?
  • 高分求解 - TOMCAT中的内存泄漏问题……
  • 进程内存泄漏的问题
  • 内存泄漏问题?
  • 内存泄漏问题跟踪 YAGAC
  • linux下内存泄漏的工具
  •  
    本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
    本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • linux下进程占用内存空间详解
  • 解析Linux系统中JVM内存2GB上限的详解
  • 深入分析Java内存区域的使用详解
  • 深入C# 内存管理以及优化的方法详解
  • 基于C++中常见内存错误的总结 iis7站长之家
  • Unix下C程序内存泄漏检测工具Valgrind的安装与使用详解
  • android内存及内存溢出分析详解
  • 深入C/C++浮点数在内存中的存储方式详解
  • 基于eclipse.ini内存设置的问题详解
  • 深入C语言内存区域分配(进程的各个段)详解
  • 如何查看进程实际的内存占用情况详解
  • 解析Android开发优化之:对Bitmap的内存优化详解
  • 基于Java内存溢出的解决方法详解
  • 解析Android获取系统cpu信息,内存,版本,电量等信息的方法详解
  • 深入内存对齐的详解
  • 深入java内存查看与分析详解
  • 基于一个简单定长内存池的实现方法详解
  • C语言内存对齐实例详解
  • 解析内存对齐 Data alignment: Straighten up and fly right的详解
  • 深入分析:用1K内存实现高效I/O的RandomAccessFile类的详解
  • C/C++内存池实现介绍及基本要求
  • 我的机器内存128 ,安装redhat9 后,可用内存很少了,如何节省内存呢?
  • linux下free命令显示的内存使用情况分析
  • 奇闻:Apache+Apache JServ 1.1.1+1G内存居然报内存不够,那位高友知道参数设置,把俺的1G内存都利用起来,感激不尽啊
  • c/c++内存堆分配和栈分配理解
  • 怎样读取指定内存地址处指定长度的内存数据???(
  • Ubuntu查看内存,进程相关命令介绍
  • 【操作系统虚拟内存和物理内存疑惑】
  • Linux 共享内存介绍及实现代码
  • 请教一个关于内存分配的问题(系统和DMA共享一块物理内存空间)
  • Linux内存文件系统(ramdisk)的三种实现方式


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3