C语言内存泄漏检测方法

内存泄漏是C语言编程中一个很常见的问题,而且由于内存泄漏所导致的问题出现较缓慢,所以不容易觉察,所以写一个简单的程序来检测内存泄漏很有必要。

     内存泄漏通常是指堆内存的泄漏,也就是通过malloc、calloc函数申请的内存,因此内存泄漏的检测方法核心思想就是通过宏定义自定义内存分配及释放函数来替换用户的malloc、calloc、free等函数。设计数据结构记录内存申请信息,申请内存时,记录并插入到全局的链表中;释放内存时从全局链表中查找对应的记录,并删除。程序结束时,将链表中信息写入文件,并清除链表。

如下所示,通过宏定义替换malloc、calloc、free等函数,并插入__FILE__、__LINE__定位语句位置。

  1. #define malloc(size) malloc_detector(size,__FILE__,__LINE__)  
  2. #define calloc(element_num,element_size) calloc_detector (element_num,element_size,__FILE__,__LINE__)  
  3. #define free(addr) free_detector(addr)  
  4.   
  5. 设计内存申请信息如下所示:  
  6.   
  7. typedef struct __info{  
  8.     void* addr;                       //the memory address   
  9.     unsigned char file[128];          //the file of the memory alloc statement   
  10.     unsigned int line;                //the line of the memory alloc statment   
  11.     unsigned int size;                //the size of the memory alloced  
  12.     }Alloc_Info;  
  13.   
  14. typedef struct __node{  
  15.     Alloc_Info info;  
  16.     Alloc_Info*next;  
  17.     }Alloc_Info_Node,*Alloc_Info_List;  
#define malloc(size) malloc_detector(size,__FILE__,__LINE__)
#define calloc(element_num,element_size) calloc_detector (element_num,element_size,__FILE__,__LINE__)
#define free(addr) free_detector(addr)

设计内存申请信息如下所示:

typedef struct __info{
    void* addr;                       //the memory address 
    unsigned char file[128];          //the file of the memory alloc statement 
    unsigned int line;                //the line of the memory alloc statment 
    unsigned int size;                //the size of the memory alloced
    }Alloc_Info;

typedef struct __node{
    Alloc_Info info;
    Alloc_Info*next;
    }Alloc_Info_Node,*Alloc_Info_List;


最终信息被写入到文件output_file中,以“w+”模式打开文件

  1. #define output_file "Leak_Detector_Report.txt"  
#define output_file "Leak_Detector_Report.txt"


在定义被替换的malloc等函数之前,必须通过undef语句将malloc等的宏定义取消,以防止出现死循环的问题,然后才可以定义替换函数

  1. #undef malloc  
  2. #undef calloc  
  3. #undef free  
  4.   
  5. malloc_detector、free_detector定义如以下代码所示。  
  6.   
  7. void *malloc_detector(size_t size,unsigned char *file,unsigned int line)  
  8. {  
  9.     void *ptr=malloc(size);  
  10.     Alloc_Info info;  
  11.     info.addr=ptr;  
  12.     info.line=line;  
  13.     info.size=size;  
  14.     strncpy(info.file,file,127);  
  15.     add_info(info);                        //Add info to the global Alloc_Info_List head  
  16.     return ptr;  
  17. }  
  18.   
  19. void free_detector(void *addr)  
  20. {   
  21.     delete_info(addr);                  //Find and Delete the info which has the address==addr from Alloc_Info_List head  
  22.     free(addr);  
  23.     /*we only detecte the memory-leak, not the wrong free-addr which not in the Alloc_Info_LIst*/  
  24. }  
#undef malloc
#undef calloc
#undef free

malloc_detector、free_detector定义如以下代码所示。

void *malloc_detector(size_t size,unsigned char *file,unsigned int line)
{
    void *ptr=malloc(size);
    Alloc_Info info;
    info.addr=ptr;
    info.line=line;
    info.size=size;
    strncpy(info.file,file,127);
    add_info(info);                        //Add info to the global Alloc_Info_List head
    return ptr;
}

void free_detector(void *addr)
{ 
    delete_info(addr);                  //Find and Delete the info which has the address==addr from Alloc_Info_List head
    free(addr);
    /*we only detecte the memory-leak, not the wrong free-addr which not in the Alloc_Info_LIst*/
}


程序结束时刻调用report_info函数保存检测信息。

  1. void report_info()  
  2. {  
  3.     FILE *fp_write=fopen(output_file,"w+");  
  4.     if(!fp_write){printf("can't open file\n");exit(1);}  
  5.     char info[sizeof(Alloc_Info)+128];  
  6.     Alloc_Info_List i=head,pre;  
  7.     if(i==NULL){  
  8.         sprintf(info,"%s","no memory leak");  
  9.         fwrite(info,strlen(info)+1,1,fp_write);  
  10.     }  
  11.     for(i=head;i!=NULL;)  
  12.     {  
  13.         sprintf(info,"memory leak:file %s line %d,addr %x,size %d\n",i->info.file,i->info.line,i->info.addr,i->info.size);  
  14.         fwrite(info,strlen(info)+1,1,fp_write);  
  15.         pre=i;  
  16.         i=i->next;  
  17.         free(pre);  
  18.     }  
  19.     flcose(fp_write);  
  20. }  
void report_info()
{
    FILE *fp_write=fopen(output_file,"w+");
    if(!fp_write){printf("can't open file\n");exit(1);}
    char info[sizeof(Alloc_Info)+128];
    Alloc_Info_List i=head,pre;
    if(i==NULL){
        sprintf(info,"%s","no memory leak");
        fwrite(info,strlen(info)+1,1,fp_write);
    }
    for(i=head;i!=NULL;)
    {
        sprintf(info,"memory leak:file %s line %d,addr %x,size %d\n",i->info.file,i->info.line,i->info.addr,i->info.size);
        fwrite(info,strlen(info)+1,1,fp_write);
        pre=i;
        i=i->next;
        free(pre);
    }
    flcose(fp_write);
}


以下两个函数为链表操作

  1. void add_info(Alloc_Info info); //add memory alloc info to Alloc_Info_List  
  2. void delete_info(void *addr);   //find and delete the alloc info       
void add_info(Alloc_Info info); //add memory alloc info to Alloc_Info_List
void delete_info(void *addr);   //find and delete the alloc info     


测试程序如下:

  1. #define DEBUG  
  2. #include<stdio.h>  
  3. #include<malloc.h>  
  4. #include"leak_detector_c.h"  
  5. extern Alloc_Info_List head;  
  6. int main()  
  7. {  
  8.     char *ptr1=malloc(100);  
  9.     char *ptr2=malloc(101);  
  10.     char *ptr3=malloc(102);  
  11.   
  12.     char *ptr4=calloc(103,1);  
  13.     char *ptr5=calloc(104,1);  
  14.     char *ptr6=calloc(105,1);  
  15.     free(ptr1);  
  16.     free(ptr6);  
  17.     report_info();  
  18. }  
#define DEBUG
#include<stdio.h>
#include<malloc.h>
#include"leak_detector_c.h"
extern Alloc_Info_List head;
int main()
{
    char *ptr1=malloc(100);
    char *ptr2=malloc(101);
    char *ptr3=malloc(102);

    char *ptr4=calloc(103,1);
    char *ptr5=calloc(104,1);
    char *ptr6=calloc(105,1);
    free(ptr1);
    free(ptr6);
    report_info();
}


测试结果如下:

  1. memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 9,addr 32620,size 101  
  2. memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 10,addr 32728,size 102  
  3. memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 12,addr 32830,size 103  
  4. memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 13,addr 33ad0,size 104  
memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 9,addr 32620,size 101
memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 10,addr 32728,size 102
memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 12,addr 32830,size 103
memory leak:file F:\个人源码库\内存泄漏处理方法\leak_detctor_c_v2\text.c line 13,addr 33ad0,size 104


    检测内存泄漏时,默认每一个free所对应的地址已经被申请,即已经保存在全局列表中,可以对删除函数进行扩充,如果搜索完整个列表都没有发现对应的alloc_info则可以判定为free出错,对于定位free error有帮助。

转自:http://blog.chinaunix.net/uid-20583479-id-1919956.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值