在windows下使用Visual Leak Detector + Visual Studio 2008进行内存泄漏分析

来源:互联网 发布:单片机电路图仿真 编辑:程序博客网 时间:2024/06/07 07:14

安装配置我就不多说了,在我的博文里有博客《 

在windows下使用 Visual Leak Detector for Visual C++ 2008的安装和配置》,链接是

http://blog.csdn.net/hitxuqin/article/details/12011953

一、使用

下面是一个简单样例,网上流传很多。

•#include <vld.h>•#include<stdio.h>•void f()•{•  int*p = new int(0x12345678);•}•intmain()•{•  f();•  return0;•}

然后在你运行完程序的时候,你会在vs2008的输出中看到Visual Leak Detector的打印信息,如图


如果你的工程不是vs2008建立的,那么最好在你的#include<vld.h>之后加入
#pragma comment(lib, "vld.lib")


二、内存泄露

这儿说一下什么是内存泄漏,我的理解:new出来的对象没有释放
Wikipedia告诉我:内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。

导致严重后果的内存泄漏有:
•程序一直运行,并且随着时间的流失消耗越来越多的内存(比如服务器上的后台任务)
•新的内存被频繁地分配,比如连接数据库,显示电脑游戏或动画视频画面时;
•内存非常有限,比如在嵌入式系统或便携设备中;
•泄漏在操作系统内部发生;
•泄漏在系统关键驱动中发生;

C++需要关注的两种类型的内存泄漏有

•堆内存泄漏(Heapleak):堆内存指的是程序运行中根据需要分配通过malloc,realloc new等从堆中分配的一块内存,完成后必须通过调用正确的 delete删掉。就是我理解的new出来的对象没有正确delete掉
•系统资源泄漏(ResourceLeak).主要指程序使用系统分配的资源比如 handle ,SOCKET等,但没有使用相应的函数释放掉,导致系统资源的浪费.

接下来说下new和delete
•New,在我们new一个对象的时候,其实做了这样三件事:
•   1)调用 operator new 的标准库函数,分配足够大的原始未类型化的内存。(没有进行构造)
•   2)运行该类型的构造函数(简单类型变量省略)
•   3)返回指向新分配并构造的对象指针。
•Delete
•  1) 调用析构函数
•   2)释放内存空间。

三、典型内存泄漏举例
接下来就是这篇博文的重点了,就是一些典型的内存泄漏的例子啦!

1、程序在某处分配内存,在另一处释放内存,但可以在中间一些地方退出,一旦有某个出口没有释放应该释放的内存,就可能发生内存泄漏。 如try语句的catch分支,函数中的多个if + return或for+break 分支都要考虑到相应内存的释放。这个是我觉得发生概率最大的了,写代码一定要记得在所有出口检查是否释放所有内存!

下面的是错误示例(正确的需要把注释去掉):

char* ch;try{ch = new char;// do something...if(i == 0)throw i;// do something...if(NULL != ch){delete ch;ch = NULL;}}catch(...){
/*if(NULL != ch){delete ch;ch = NULL;}*/} // catch里面没有判断释放内存


2、new与delete未匹配,array new/array delete未匹配

这个老生长谈了,从我们知道new的第一天起,老师就告诉我们new和delete要成对出现


3、类动态分配的成员变量,在析构函数中没有全部进行判断释放内存。

 if(NULL != m_ptrData){       delete m_ptrData;       m_ptrData = NULL;// 释放的指针指NULL可以防止野指针的产生}


4、释放对象数组时,没有使用delete [],基本数据类型不会有这个问题

下面的是错误示例(正确的需要把注释去掉):

B* b = new B[5];// do something...delete b; // vs2008编译通过,执行出错// 正确方法:// delete[] b;// 方括号的存在会使编译器获取数组大小然后析构函数再被依次应用在每个对象上。

5、指向由指向对象的指针构成的数组的内存释放不能用简单的delete[]

我的理解是指向由指向对象的指针构成的数组

下面的是错误示例(正确的需要把注释去掉):

B** b = new B*[3];for (int i = 0; i < 3; ++i){ b[i] = new B; }// do something...delete[] b; error//for (int i = 0; i < 3; ++i)//{//delete b[i]; //}//delete[] b;// 也可用delete b,因为内存连续分配

6、没将基类的析构函数定义成虚函数

内存泄漏发生在用一个基类的指针类型来删除一个派生类的对象,派生类的构造函数有申请内存,但是即使你正确的写了派生类的析构函数,只有把把基类的析构函数写成虚函数,才能调用派生类的析构函数来释放内存,否则就发生内存泄漏了

下面的是错误示例(正确的需要把注释去掉):

#include <vld.h>#include <stdlib.h>#include <stdio.h>#include <iostream>using namespace std;class base{public:base(){cout << "in base construction function!" << endl;}//virtual~base(){cout << "in base destruction function!" << endl;}};class devired : public base{public:devired(){m_ch = new char;cout << "in devired construction function!" << endl;}~devired(){if(NULL != m_ch){delete m_ch;m_ch = NULL;}cout << "in devired destruction function!" << endl;}private:char* m_ch;};int main(){base* d = new devired;delete d;system("pause");}

•7、没有以独立的语句将newed对象存放到智能指针内(Effective C++条款)
 错误的函数调用:func(auto_ptr<Widget>(new Widget()),priority());

你的意图是:
1、调用Widget的构造函数。 2、调用auto_ptr<Widget>的构造函数。 3、调用Priority函数。

编译器可能按下面次序执行:
1、调用Widget的构造函数。 2、调用Priority函数。 3、调用auto_ptr<Widget>的构造函数。

解决方式:由于编译器没法对“跨越语句块的各项操作”重新排列,所以可以将语句拆分
auto_ptr<Widget> pw(new Widget());  
processWidger(pw,priority());  

下面的是错误示例

#include <vld.h>#include <iostream>  #include <memory>  using namespace std;    class Widget  {  private:char* m_char;public:      Widget()      {  m_char = new char;        cout<<"Widget()"<<endl;      }        ~Widget()      {  if(NULL != m_char){delete m_char;m_char = NULL;}        cout<<"~Widget()"<<endl;      }  };    int priority()  {  int i = 0; if(i == 0)throw i;return 0; }    void func(auto_ptr<Widget> pw,int priority){}   int main()  {  try{func(auto_ptr<Widget>(new Widget()),priority()); }catch(...){;}    system("pause");      return 0;  }


8、有些类型对象如CDialog,CWindow,CFile,CImage等需要在Delete前做Close、Release、Destroy等操作的,Delete时检查是否已经调用了相应的扫尾函数。


四、感想

接下来说一下我的一点小感想,在整理内存泄漏工具的时候,自己学到了很多,虽然还有很多不会,但是加油吧,路都是人一步一步走出来的~