博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重载new和delete来检测内存泄漏
阅读量:6377 次
发布时间:2019-06-23

本文共 4484 字,大约阅读时间需要 14 分钟。

1. 简述

    内存泄漏属于资源泄漏的一种,百度百科将内存泄漏分为四种:常发性内存泄漏、偶发性内存泄漏、一次性内存泄漏和隐式内存泄漏。

    常发性指:内存泄漏的代码会被多次执行到。偶发性指:内存泄漏的代码只有在特定的条件下才会执行到。一次性指:内存泄漏的代码只会被执行到一次。隐式指:程序在运行中不断的开辟内存,知道程序结束时才释放内存,本质上虽然没有内存泄漏,但是如果这个程序在连续运行很长时间,会耗尽所有内存,导致系统崩溃。
    下面首先介绍内存检测的基本原理,然后给出代码样例,最后说明针对四种内存泄漏进行检测的想法。

2. 基本原理

    内存泄漏就是new出来的内存没有通过delete合理的释放掉。new和delete这两个函数就是关键点。可以重载new和delete,每次new中开辟一块内存就用链表把这个内存的信息保存下来,每次用delete删除一块内存就从链表中删除这块内存的记录。

3. 代码样例

  1 
#include
<
iostream
>
  2 
using
 
namespace
 std;
  3 
//
---------------------------------------------------------------
  4 
//
 内存记录
  5 
//
---------------------------------------------------------------
  6 
class
 MemInfo {
  7 
private
:
  8 
  
void
*
 ptr;
  9 
  
const
 
char
*
 file;
 10 
  unsigned 
int
 line;
 11 
  MemInfo
*
 link;
 12 
  friend 
class
 MemStack;
 13 
};
 14 
//
---------------------------------------------------------------
 15 
//
 内存记录栈 
 16 
//
---------------------------------------------------------------
 17 
class
 MemStack {
 18 
private
:
 19 
  MemInfo
*
 head;
 20 
public
:
 21 
  MemStack():head(NULL) { }
 22 
  
~
MemStack() { 
 23 
    MemInfo
*
 tmp;
 24 
    
while
(head 
!=
 NULL) {
 25 
      free(head
->
ptr); 
//
 释放泄漏的内存 
 26 
      tmp 
=
 head
->
link;
 27 
      free(head);
 28 
      head 
=
 tmp;
 29 
    }
 30 
  }
 31 
  
void
 Insert(
void
*
 ptr, 
const
 
char
*
 file, unsigned 
int
 line) {
 32 
    MemInfo
*
 node 
=
 (MemInfo
*
)malloc(
sizeof
(MemInfo));
 33 
    node
->
ptr 
=
 ptr; node
->
file 
=
 file; node
->
line
=
line;
 34 
    node
->
link 
=
 head; head 
=
 node;    
 35 
  }
 36 
  
void
 Delete(
void
*
 ptr) {
 37 
    MemInfo
*
 node 
=
 head;
 38 
    MemInfo
*
 pre 
=
 NULL;
 39 
    
while
(node 
!=
 NULL 
&&
 node
->
ptr
!=
ptr) {
 40 
      pre 
=
 node;
 41 
      node 
=
 node
->
link;
 42 
    }
 43 
    
if
(node 
==
 NULL)
 44 
      cout 
<<
 
"
删除一个没有开辟的内存
"
 
<<
 endl;
 45 
    
else
 {
 46 
      
if
(pre 
==
 NULL) 
//
 删除的是head 
 47 
        head 
=
 node
->
link;
 48 
      
else
 
 49 
        pre
->
link 
=
 node
->
link;
 50 
      free(node);
 51 
    }
 52 
  }
 53 
  
void
 Print() {
 54 
    
if
(head 
==
 NULL) {
 55 
      cout 
<<
 
"
内存都释放掉了
"
 
<<
 endl; 
 56 
      
return
;
 57 
    }
 58 
    cout 
<<
 
"
有内存泄露出现
"
 
<<
 endl; 
 59 
    MemInfo
*
 node 
=
 head;    
 60 
    
while
(node 
!=
 NULL) {
 61 
      cout 
<<
 
"
文件名: 
"
 
<<
 node
->
file 
<<
 
"
 , 
"
 
<<
 
"
行数: 
"
 
<<
 node
->
line 
<<
 
"
 , 
"
 62 
        
<<
 
"
地址: 
"
 
<<
 node
->
ptr 
<<
 endl; 
 63 
      node 
=
 node
->
link;
 64 
    }
 65 
  }
 66 
};
 67 
//
---------------------------------------------------------------
 68 
//
 全局对象 mem_stack记录开辟的内存 
 69 
//
---------------------------------------------------------------
 70 
MemStack mem_stack;
 71 
//
---------------------------------------------------------------
 72 
//
 重载new,new[],delete,delete[] 
 73 
//
---------------------------------------------------------------
 74 
void
*
 
operator
 
new
(size_t size, 
const
 
char
*
 file, unsigned 
int
 line) {
 75 
  
void
*
 ptr 
=
 malloc(size);
 76 
  mem_stack.Insert(ptr, file, line);
 77 
  
return
 ptr;
 78 
}
 79 
void
*
 
operator
 
new
[](size_t size, 
const
 
char
*
 file, unsigned 
int
 line) {
 80 
  
return
 
operator
 
new
(size, file, line); 
//
 不能用new 
 81 
}
 82 
void
 
operator
 delete(
void
*
 ptr) {
 83 
  free(ptr);
 84 
  mem_stack.Delete(ptr);
 85 
}
 86 
void
 
operator
 delete[](
void
*
 ptr) {
 87 
  
operator
 delete(ptr);
 88 
}
 89 
//
---------------------------------------------------------------
 90 
//
 使用宏将带测试代码中的new和delte替换为重载的new和delete 
 91 
//
---------------------------------------------------------------
 92 
#define
 new new(__FILE__,__LINE__)
 93 
//
---------------------------------------------------------------
 94 
//
 待测试代码 
 95 
//
---------------------------------------------------------------
 96 
void
 bad_code() {
 97 
  
int
 
*
=
 
new
 
int
;
 98 
  
char
 
*
=
 
new
 
char
[
5
];
 99 
  delete []q;
100 
101 
102 
void
 good_code() {
103 
  
int
 
*
=
 
new
 
int
;
104 
  
char
 
*
=
 
new
 
char
[
5
];
105 
  delete p;
106 
  delete []q;
107 
108 
//
---------------------------------------------------------------
109 
//
 测试过程 
110 
//
---------------------------------------------------------------
111 
int
 main() {
112 
  good_code();
113 
  bad_code();
114 
  mem_stack.Print();
115 
  system(
"
PAUSE
"
);
116 
  
return
 
0
;
117 
}

    输出结果为:

    
    可见97行开辟的int,没有delete掉,输出结果也显示为97行。

4. 代码说明

4.1 关于new的参数问题。

    对于new int,编译器会解释为new(sizeof(int)),对于new int[5],编译器会解释为new(sizeof(int)*5)。因此使用宏定义预编译后,new int就变为new (__FILE__,__LINE__) int,编译器会解释为new(sizeof(int), __FILE__,__LINE__)。

4.2 关于MemStack

    MemStack内部也是一个链表结构,注意内部实现不能使用new和delete,只能使用malloc和free来实现链表,因为待测代码中的重载new和delete中调用了MemStack的insert和delete函数,如果insert和delete函数也调用重载后的new和delete的话,会构成死循环的,所以直接使用free和malloc比较好。
    MemStack中的析构函数,会释放掉泄漏掉的内存。

5. 使用思考

    对于常发性和一次性的内存泄漏代码,直接放入测试就好了。对于偶发性的内存泄漏代码,只要满足特定条件,那么也就转化为常发性或者一次性的内存泄漏了。

    对于隐式内存泄漏,由于程序是在很长一段时间之后导致内存耗尽,我们需要长时间观察,每隔一段时间比较一下内存的使用量,如果在一个较长的时间内,内存使用量持续增加,那么可以考虑是内存泄漏。不过调试起来可能会比较麻烦,还是需要重新审视程序设计的。

6. 参考

    百度百科_内存泄漏:介绍内存泄漏的基本分类。

   
    如何检查内存泄漏-重载new和delete:十分生动的说明。
   
    一个跨平台的C++内存泄漏检测器:十分专业化的讲解和实现。
   

转载地址:http://batqa.baihongyu.com/

你可能感兴趣的文章
jQuery基础三
查看>>
已Access为支持,书写一个C#写入的记录的方案
查看>>
JavaScript自适应调整文字大小
查看>>
实验报告一:网络侦查与网络扫描
查看>>
.net 接入微信商户企业支付API 问题总结
查看>>
防止SQL注入
查看>>
java中的动态代理(三)
查看>>
Ue4的UE_LOG
查看>>
自绘制HT For Web ComboBox下拉框组件
查看>>
基于 HTML5 WebGL 的低碳工业园区监控系统
查看>>
小机房的树CODEVS 2370
查看>>
得到一个范围的随机数函数
查看>>
js返回上一页并刷新、返回上一页、自动刷新页面
查看>>
复数类完整实现 + 四则运算符重载
查看>>
UVA 699 The Falling Leaves 数据结构
查看>>
简单搜索专题的笔记
查看>>
ASP汉字转拼音函数的方法
查看>>
MySQL判断字段值来确定是否插入新记录
查看>>
HTTP协议漫谈 --笔记
查看>>
react实现点击某个元素之外自动隐藏此元素
查看>>