linux C内存泄露检测实现及内存泄露检测的一般方法

linux中,由于使用malloc或alloc而没有free掉申请的内存,就会造成内存的泄露。通常,来讲为了避免内存泄露的情况出现,一般要求,我们尽量的malloc之后,调用free。但是总会有忘记free的时候啊。一般可以有如下几种方式来避免内存泄露:

1)  使用智能指针,这个在C++中较为常见;

2)  使用内存池;

3)  自己封装一层malloc/free等等。当申请内存时,将申请信息放入到一个已分配内存信息链表里面。free时,删除对应的信息表的节点。在程序执行结束前,扫瞄该信息表,若还存在信息节点,那么该节点记录的就是泄露的内存信息。若链表为空,那就是说没有发生内存泄露;

4)使用检测工具检测内存泄露,进而修补程序,这样的工具有比如Valgrind等等。

以下,给出一个按方式3实现的内存泄露检测的实现版本,代码量本身不多。

leak_detector_c.h文件

 #ifndef  LEAK_DETECTOR_C_H
  #define  LEAK_DETECTOR_C_H
  
  #define  FILE_NAME_LENGTH          256
  #define  OUTPUT_FILE               "/home/leak_info.txt" /*this file should be created first!*/
  #define  malloc(size)               xmalloc (size, __FILE__, __LINE__)
  #define  calloc(elements, size)     xcalloc (elements, size, __FILE__, __LINE__)
  #define  free(mem_ref)              xfree(mem_ref)
  
  struct _MEM_INFO
  {
      void            *address;
      unsigned int    size;
      char            file_name[FILE_NAME_LENGTH];
      unsigned int    line;
  };
  typedef struct _MEM_INFO MEM_INFO;
  
  struct _MEM_LEAK {
      MEM_INFO mem_info;
      struct _MEM_LEAK * next;
  };
  typedef struct _MEM_LEAK MEM_LEAK;
  
  void add(MEM_INFO alloc_info);
  void erase(unsigned pos);
  void clear(void);
  
  void * xmalloc(unsigned int size, const char * file, unsigned int line);
  void * xcalloc(unsigned int elements, unsigned int size, const char * file, unsigned int line);
  void xfree(void * mem_ref);
  
  void add_mem_info (void * mem_ref, unsigned int size,  const char * file, unsigned int line);
  void remove_mem_info (void * mem_ref);
  void report_mem_leak(void);
  
 #endif

leak_detector_c.c文件

#include    <stdio.h>
#include    <malloc.h>
#include    <string.h>
#include    "leak_detector_c.h"
 
#undef      malloc
#undef      calloc
#undef      free
  
  
static MEM_LEAK * ptr_start = NULL;
static MEM_LEAK * ptr_next =  NULL;

/*
* adds allocated memory info. into the list
*
*/
void add(MEM_INFO alloc_info)
{

     MEM_LEAK * mem_leak_info = NULL;
     mem_leak_info = (MEM_LEAK *) malloc (sizeof(MEM_LEAK));
     mem_leak_info->mem_info.address = alloc_info.address;
     mem_leak_info->mem_info.size = alloc_info.size;
     strcpy(mem_leak_info->mem_info.file_name, alloc_info.file_name); 
     mem_leak_info->mem_info.line = alloc_info.line;
     mem_leak_info->next = NULL;
 
    if (ptr_start == NULL)  
    {
        ptr_start = mem_leak_info;
        ptr_next = ptr_start;
    }
    else {
        ptr_next->next = mem_leak_info;
        ptr_next = ptr_next->next;               
    }

}
/*
  * erases memory info. from the list
  *
*/
void erase(unsigned pos)
{
 
     unsigned index = 0;
     MEM_LEAK * alloc_info, * temp;
      
      if(pos == 0)
      {
          MEM_LEAK * temp = ptr_start;
          ptr_start = ptr_start->next;
          free(temp);
      }
      else 
      {
          for(index = 0, alloc_info = ptr_start; index < pos; 
              alloc_info = alloc_info->next, ++index)
          {
              if(pos == index + 1)
              {
                  temp = alloc_info->next;
                  alloc_info->next =  temp->next;
                 if(temp->next==NULL)
                  {
                    ptr_next = alloc_info;
                  }
                  free(temp);
                  break;
              }
          }
      }
  }
  
  /*
   * deletes all the elements from the list
   */
  void clear()
  {
      MEM_LEAK * temp = ptr_start;
      MEM_LEAK * alloc_info = ptr_start;
  
      while(alloc_info != NULL) 
      {
          alloc_info = alloc_info->next;
          free(temp);
          temp = alloc_info;
      }
      ptr_start=NULL;
  }
  
  /*
   * replacement of malloc
   */
  void * xmalloc (unsigned int size, const char * file, unsigned int line)
  {
      void * ptr = malloc (size);
      if (ptr != NULL) 
      {
          add_mem_info(ptr, size, file, line);
      }
      return ptr;
  }
  
  /*
   * replacement of calloc
   */
  void * xcalloc (unsigned int elements, unsigned int size, const char * file, unsigned int line)
  {
      unsigned total_size;
      void * ptr = calloc(elements , size);
      if(ptr != NULL)
      {
          total_size = elements * size;
          add_mem_info (ptr, total_size, file, line);
      }
      return ptr;
  }
  
  
  /*
   * replacement of free
   */
  void xfree(void * mem_ref)
  {
      remove_mem_info(mem_ref);
      free(mem_ref);
  }
  
/*
* gets the allocated memory info and adds it to a list
*
*/
  void add_mem_info (void * mem_ref, unsigned int size,  const char * file, unsigned int line)
  {
     MEM_INFO mem_alloc_info;
 
     /* fill up the structure with all info */
     memset( &mem_alloc_info, 0, sizeof ( mem_alloc_info ) );
      mem_alloc_info.address  = mem_ref;
      mem_alloc_info.size = size;
      strncpy(mem_alloc_info.file_name, file, FILE_NAME_LENGTH);
     mem_alloc_info.line = line;
     
     /* add the above info to a list */
      add(mem_alloc_info);
 }
  
  /*
   * if the allocated memory info is part of the list, removes it
  *
  */
 void remove_mem_info (void * mem_ref)
 {
    unsigned short index;
     MEM_LEAK  * leak_info = ptr_start;
 
     /* check if allocate memory is in our list */
    for(index = 0; leak_info != NULL; ++index, leak_info = leak_info->next)
    {
        if ( leak_info->mem_info.address == mem_ref )
        {
             erase ( index );
             break;
        }
    }
}

/*
  * writes all info of the unallocated memory into a file
  */
 void report_mem_leak(void)
{
    unsigned short index;
    MEM_LEAK * leak_info;


    FILE * fp_write = fopen (OUTPUT_FILE, "w+");
    char info[1024];


     if(fp_write != NULL)
     {
         sprintf(info, "%s\r\n", "Memory Leak Summary");
         fwrite(info, (strlen(info)) , 1, fp_write);
         sprintf(info, "%s\r\n", "-----------------------------------");
         fwrite(info, (strlen(info)) , 1, fp_write);


        for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next)
        {
             sprintf(info, "address : %d\r\n", leak_info->mem_info.address);
             fwrite(info, (strlen(info)) , 1, fp_write);
             sprintf(info, "size    : %d bytes\r\n", leak_info->mem_info.size);
             fwrite(info, (strlen(info)) , 1, fp_write);
             sprintf(info, "file    : %s\r\n", leak_info->mem_info.file_name);
             fwrite(info, (strlen(info)) , 1, fp_write);
             sprintf(info, "line    : %d\r\n", leak_info->mem_info.line);
             fwrite(info, (strlen(info)) , 1, fp_write);
             sprintf(info, "%s\r\n", "-----------------------------------");
             fwrite(info, (strlen(info)) , 1, fp_write);


             printf("addr=%d,size=%d,file=%s,line=%d\n"
                ,leak_info->mem_info.address
                ,leak_info->mem_info.size
                ,leak_info->mem_info.file_name
                ,leak_info->mem_info.line);
        }


        fclose(fp_write);
      }
      else
      {


      }
      /*clear();*/
}

使用时,只需将以上两个文件放入到你的工程目录下,并在主函数里面调用report_mem_leak就OK了。

测试test.c文件

#include    "leak_detector_c.h"
int main()
{
    char * ptr1 = (char *)malloc(10);
    int * ptr2 = (int *)calloc(10, sizeof(int));
    float * ptr3 = (float *) calloc(15, sizeof(float));
    free(ptr2);
atexit(report_mem_leak);
return 0;
}

编译test.c并运行,可以在/home/leak_info.txt文件中,看到两条内存泄露记录。

总的来说,这样的检测方式还是有一定效果的,但是同时内存信息链表节点也使用了malloc来申请内存,这就造成了一定的额外的内存开销。

我觉得要避免内存泄露,首先是自身要养成良好的编程习惯,然后是使用相关的方法和工具对代码进行检测,最后是要阅读代码了。工具也并不能检测出所有的内存泄露,在这个时候只能靠自己去阅读代码分析代码了,人毕竟比机器灵活嘛!

 

Valgrind移植powerpc


./autogen.sh


./configure --host=powerpc-linux CC=powerpc-linux-gnu-gcc CPP=powerpc-linux-gnu-cpp CXX=powerpc-linux-gnu-g++ --prefix=/mnt/nand


make


make install



 ./valgrind --tool=memcheck --vgdb=no ./memleak 


注意:

1. --prefix=/mnt/nand 指定的目录要与开发板上放置的目录一致

2. 参数必须  --vgdb=no 否则会如下错误(可能因为我嵌入式linux 没有集成gdb)


root@xxx:/mnt/nand/bin# ./valgrind --tool=memcheck ./memleak 
==1300== Memcheck, a memory error detector
==1300== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1300== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==1300== Command: ./memleak
==1300== 
==1300== error 2 No such file or directory
==1300== mknod /tmp/vgdb-pipe-from-vgdb-to-1300-by-root-on-/bin/hostname
==1300== valgrind: fatal error: vgdb FIFOs cannot be created.


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值