ITPub博客

首页 > IT职业 > IT职场 >  软件测试学习教程——重载new或delete来检测内存泄漏

 软件测试学习教程——重载new或delete来检测内存泄漏

IT职场 作者:千锋教育官方 时间:2019-09-10 16:17:22 0 删除 编辑

 1. 简述

 

  在日常生活中,例如电脑,还有我们大家每天离不开的手机,用的时间久了,就会发现运行速度越来越快,用方言讲,就是卡的不行啦, 电脑或手机出现这种情况,大家势必会感到非常烦躁,有那种摔电脑或手机的冲动。

 

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

 

  常发性指:内存泄漏的代码会被多次执行到。偶发性指:内存泄漏的代码只有在特定的条件下才会执行到。一次性指:内存泄漏的代码只会被执行到一次。隐式指:程序在运行中不断的开辟内存,知道程序结束时才释放内存,本质上虽然没有内存泄漏,但是如果这个程序在连续运行很长时间,会耗尽所有内存,导致系统崩溃。

 

  下面首先介绍内存检测的基本原理,然后给出代码样例,最后说明针对四种内存泄漏进行检测的想法。

 

  2. 基本原理

 

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

 

  #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*p=new int;

 

  98 char*q=new char[5];

 

  99 delete[]q;

 

  100}

 

  101

 

  102 void good_code(){

 

  103 int*p=new int;

 

  104 char*q=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}

 

  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. 使用思考

 

  对于常发性和一次性的内存泄漏代码,直接放入测试就好了。对于偶发性的内存泄漏代码,只要满足特定条件,那么也就转化为常发性或者一次性的内存泄漏了。对于隐式内存泄漏,由于程序是在很长一段时间之后导致内存耗尽,我们需要长时间观察,每隔一段时间比较一下内存的使用量,如果在一个较长的时间内,内存使用量持续增加,那么可以考虑是内存泄漏。不过调试起来可能会比较麻烦,还是需要重新审视程序设计的。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69914734/viewspace-2656639/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
千锋IT职业教育——做真实的自己 用良心做教育

注册时间:2019-03-28

  • 博文量
    140
  • 访问量
    92335