设为首页收藏本站

猿媛之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

快捷导航
搜索
热搜: 活动 交友 discuz
查看: 4646|回复: 0

C/C++(面试) 如何自定义函数进行内存泄露检测

[复制链接]

554

主题

556

帖子

1936

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
1936
发表于 2020-11-12 14:58:01 | 显示全部楼层 |阅读模式
         在C/C++程序开发的时候经常需要使用malloc/free对内存进行申请与释放,如果在使用malloc后却忘记了调用free对内存进行释放,此时就造成了内存泄露,随着时间的推移会慢慢消耗掉系统所有的内存,导致程序无法继续运行,而往往这种内存泄露的问题在大型项目中是很难被定位的,如何通过自定义函数的方法很容易地检测到内存的泄露呢?
        主要解决方法为:通过自定义内存申请和释放的方法mymalloc和myfree,然后设置一个钩子,让用户在调用malloc/free的时候会调用自定义的myalloc/free函数,然后通过下面的宏定义实现当malloc被调用的时候就会默认调用mymalloc函数的功能:

  1. #define  malloc(size)               mymalloc (size, __FILE__, __LINE__)
复制代码
       需要注意的是在调用mymalloc的时候多传入了两个参数__FILE__和 __LINE__,它们分别表示调用mymalloc的代码所在的文件以及行号。有了这些信息以后,主要的实现方法为:        自定义一个列表,每当malloc函数被调用的时候,mymalloc被调用的时候,首先通过调用系统函数malloc把内存申请好,然后把调用者的信息(调用者所在的文件和行号)以及申请好内存的信息添加到列表中;当myfree被调用的时候,首先通过调用系统函数free释放的对应的内存,然后根据待释放的内存地址在列表中删除记录这块内存申请的信息。实现代码如下:
leak_detector.h
  1. #ifndef  LEAK_DETECTOR_C_H
  2. #define  LEAK_DETECTOR_C_H

  3. #pragma  (report_mem_leak)
  4. #define  FILE_NAME_LENGTH              256   //used to store file name in whitch calls malloc
  5. #define  CALL_DEPTH                 10   //repesesent the max fuction call level
  6. #define  TIME_LEN                  26     //time string length
  7. #define  OUTPUT_FILE                           "leak_info.txt"   //store memory leak info
  8. #define  malloc(size)                                mymalloc (size, __FILE__, __LINE__)
  9. #define  calloc(elements, size)          mycalloc (elements, size, __FILE__, __LINE__)
  10. #define  realloc(address, size)     myrealloc(address, size, __FILE__, __LINE__)
  11. #define  free(mem_ref)                                    myfree(mem_ref)

  12. struct _MEM_TRACE_INFO {
  13.     char** traceInfo;     //backtrace information malloc is called
  14.     size_t size;          //number of track infos
  15. };
  16. typedef struct _MEM_TRACE_INFO MEM_TRACE_INFO;

  17. struct _MEM_INFO
  18. {
  19.     void                          *address;
  20.     unsigned int          size;
  21.     char                          file_name[FILE_NAME_LENGTH];
  22.     unsigned int          line;
  23.     char              allocTime[TIME_LEN];
  24.     MEM_TRACE_INFO*   traceInfo;
  25. };
  26. typedef struct _MEM_INFO MEM_INFO;

  27. struct _MEM_LEAK {
  28.         MEM_INFO mem_info;
  29.         struct _MEM_LEAK * next;
  30. };
  31. typedef struct _MEM_LEAK MEM_LEAK;

  32. static void add(MEM_INFO alloc_info);    //add a allocated info to the linkedlist
  33. static void erase(void * address);       //remove a allocted info from the linkedlist
  34. static void clear(void);                 //free the heap space that stores the memory leak info

  35. void * mymalloc(unsigned int size, const char * file, unsigned int line);          //replace malloc
  36. void * mycalloc(unsigned int elements, unsigned int size, const char * file, unsigned int line); //replace calloc
  37. void * myrealloc(void* address, unsigned int size, const char * file, unsigned int line); //replace realloc
  38. void myfree(void * mem_ref);   //replace free

  39. static void add_mem_info (void * mem_ref, unsigned int size,  const char * file, unsigned int line,MEM_TRACE_INFO* traceinfo);
  40. static void remove_mem_info (void * mem_ref);
  41. void report_mem_leak(void) __attribute__((destructor));

  42. #endif

复制代码
leak_detector.c:
  1. #include        <stdio.h>
  2. #include        <malloc.h>
  3. #include        <string.h>
  4. #include    <time.h>
  5. #include <execinfo.h>

  6. #include        "leak_detector.h"

  7. #undef                malloc
  8. #undef                calloc
  9. #undef      realloc
  10. #undef                 free


  11. static MEM_LEAK * ptr_start = NULL; //list head
  12. static MEM_LEAK * ptr_end =  NULL;  //list tail


  13. /*
  14. * get function call trace information
  15. * return a pointer to trace info
  16. */
  17. MEM_TRACE_INFO* getTrackInfo() {
  18.   void *array[CALL_DEPTH];
  19.   size_t size;
  20.   size = backtrace(array, 10);
  21.   char** trace=backtrace_symbols(array, size);
  22.   MEM_TRACE_INFO* traceInfo=(MEM_TRACE_INFO*)malloc(sizeof(MEM_TRACE_INFO));
  23.   if(traceInfo == NULL)
  24.           return NULL;
  25.   traceInfo->size=size;
  26.   traceInfo->traceInfo=trace;
  27.   return traceInfo;
  28. }




  29. /*
  30. * adds allocated memory info into likedlist
  31. *
  32. */
  33. void add(MEM_INFO alloc_info)
  34. {
  35.     printf("add new allocation info:%d\n",(int)alloc_info.address);
  36.     MEM_LEAK* mem_leak_info=NULL;
  37.         mem_leak_info=(MEM_LEAK*)malloc(sizeof(MEM_LEAK));
  38.     mem_leak_info->mem_info.address=alloc_info.address;
  39.         mem_leak_info->mem_info.size=alloc_info.size;
  40.         strcpy(mem_leak_info->mem_info.file_name,alloc_info.file_name);
  41.         mem_leak_info->mem_info.line=alloc_info.line;
  42.         mem_leak_info->mem_info.traceInfo=alloc_info.traceInfo;
  43.     strncpy(mem_leak_info->mem_info.allocTime, alloc_info.allocTime,TIME_LEN);


  44.     if (ptr_start == NULL)  //the list has no node
  45.     {
  46.         ptr_start = mem_leak_info;
  47.         ptr_end = ptr_start;
  48.     }
  49.     else {                  //add allocated info into the tail of list
  50.         ptr_end->next = mem_leak_info;
  51.         ptr_end = ptr_end->next;
  52.     }

  53. }

  54. /*
  55. * remove memory info(address) from the list
  56. *
  57. */

  58. void erase(void* address){
  59.     MEM_LEAK * temp = ptr_start;
  60.     MEM_LEAK * pre;
  61.     if(temp != NULL && temp->mem_info.address == address){ //if the node is the head of the list
  62.         ptr_start=temp->next;
  63.         free(temp->mem_info.traceInfo);   //release space that stores traceInfo
  64.         free(temp);                       //release space that stores list node
  65.         return;
  66.     }

  67.     if(temp->next != NULL){
  68.         pre=temp;
  69.         temp=temp->next;
  70.         for(; temp != NULL; pre=temp, temp=temp->next){
  71.             if(temp->mem_info.address == address){    //find the node
  72.                 pre->next = temp->next;
  73.                 if(temp->next == NULL)     //the node to be removed is the tail of the list
  74.                     ptr_end=pre;
  75.                 free(temp->mem_info.traceInfo);   //free space for traceinfo
  76.                 free(temp);                     //free space for list node
  77.                 break;
  78.             }
  79.         }
  80.     }

  81. }

  82. /*
  83. * deletes all the elements from the list and free the space
  84. */
  85. void clear()
  86. {
  87.     MEM_LEAK * temp = ptr_start;
  88.     MEM_LEAK * alloc_info = ptr_start;

  89.     while(alloc_info != NULL)
  90.     {
  91.         alloc_info = alloc_info->next;
  92.         free(temp->mem_info.traceInfo);
  93.         free(temp);
  94.         temp = alloc_info;
  95.     }
  96. }

  97. /*
  98. * replacement of malloc
  99. */
  100. void * mymalloc (unsigned int size, const char * file, unsigned int line)
  101. {
  102.     void * ptr = malloc (size);   
  103.     if (ptr != NULL)
  104.     {  
  105.                 MEM_TRACE_INFO* traceinfo=getTrackInfo();
  106.         add_mem_info(ptr, size, file, line,traceinfo);
  107.     }
  108.     return ptr;
  109. }

  110. /*
  111. * replacement of calloc
  112. */
  113. void * mycalloc (unsigned int elements, unsigned int size, const char * file, unsigned int line)
  114. {
  115.     unsigned total_size;
  116.     void * ptr = calloc(elements , size);
  117.     if(ptr != NULL)
  118.     {
  119.                 MEM_TRACE_INFO* traceinfo=getTrackInfo();
  120.         total_size = elements * size;
  121.         add_mem_info (ptr, total_size, file, line,traceinfo);
  122.     }
  123.     return ptr;
  124. }

  125. /*
  126. * replacement of malloc
  127. */
  128. void* myrealloc(void* address, unsigned int size, const char * file, unsigned int line){
  129.     printf("realloc\n");
  130.     unsigned total_size;
  131.     void* ptr=realloc(address,size);
  132.     if(ptr!=NULL){
  133.         MEM_TRACE_INFO* traceinfo=getTrackInfo();
  134.         remove_mem_info(address);
  135.         add_mem_info(address, size, file, line ,traceinfo);
  136.     }
  137. }

  138. /*
  139. * replacement of free
  140. */
  141. void myfree(void * mem_ref)
  142. {
  143.     remove_mem_info(mem_ref);
  144.     free(mem_ref);
  145. }

  146. /*
  147. * gets the allocated memory info and adds it to a list
  148. *
  149. */
  150. void add_mem_info (void * mem_ref, unsigned int size,  const char * file, unsigned int line,MEM_TRACE_INFO* traceinfo)
  151. {
  152.     MEM_INFO mem_alloc_info;
  153.         memset(&mem_alloc_info,0,sizeof(mem_alloc_info));
  154.     mem_alloc_info.address = mem_ref;
  155.     mem_alloc_info.size = size;
  156.     strcpy(mem_alloc_info.file_name, file);
  157.     mem_alloc_info.line = line;
  158.     mem_alloc_info.traceInfo=traceinfo;
  159.     time_t timeP = time(0);
  160.     char* t=ctime(&timeP);
  161.     strncpy(mem_alloc_info.allocTime, t,TIME_LEN);


  162.     /* add the above info to a list */
  163.     add(mem_alloc_info);
  164. }

  165. /*
  166. * if the allocated memory info is part of the list, removes it
  167. *
  168. */
  169. void remove_mem_info (void * mem_ref)
  170. {
  171.     erase(mem_ref);
  172. }

  173. /*
  174. * writes all info of the unallocated memory into a file
  175. */
  176. void report_mem_leak(void)
  177. {
  178.     unsigned int i;
  179.     printf("%s","mem_leak");
  180.     unsigned short index;
  181.     MEM_LEAK * leak_info;

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

  184.     if(fp_write != NULL)
  185.     {
  186.         fprintf(fp_write, "%s\n", "Memory Leak Summary");
  187.         fprintf(fp_write, "%s\n", "-----------------------------------");

  188.         for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next)
  189.         {
  190.             fprintf(fp_write, "address : %x\n", (int)leak_info->mem_info.address);
  191.             fprintf(fp_write, "size    : %d bytes\n", leak_info->mem_info.size);
  192.             fprintf(fp_write, "file    : %s\n", leak_info->mem_info.file_name);

  193.             fprintf(fp_write, "line    : %d\n", leak_info->mem_info.line);
  194.                  fprintf(fp_write, "Time    : %s\n", leak_info->mem_info.allocTime);
  195.             fprintf(fp_write, "traceInfo    :\n");
  196.             for(i=2;i<leak_info->mem_info.traceInfo->size-2;i++){
  197.                 fprintf(fp_write, " %s\n", leak_info->mem_info.traceInfo->traceInfo[i]);
  198.             }
  199.             fprintf(fp_write, "%s\n", "-----------------------------------");
  200.         }
  201.     }
  202.     clear();
  203. }

复制代码

test.c:

  1. /***************************************************/
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include "leak_detector.h"

  5. /*********************************/
  6. /*Correct use of MALLOC and FREE */
  7. /*********************************/

  8. //Protoytpe simple function
  9. void modify(double *);
  10. void leak(int);

  11. //Main program
  12. int main()
  13. {

  14.                 //Define the size of Array
  15.                 int SIZE=100, i;

  16.                 //Define the array starting point pointer.
  17.                 double *array;

  18.                 //Allocate memory for doubles
  19.                 array = (double *)malloc(sizeof(double)*SIZE + 1);

  20.                 //Check the memory was allocated
  21.                 if (array==NULL){
  22.                                 printf("Memory could not be allocated \n");
  23.                 }
  24.                 else {
  25.                                 printf("Memory was allocated – remember to free\n \n");

  26.                                 //Modify only the first 10 elements via a function.
  27.                                 //Modify global variable from within function.
  28.                                 modify(array);

  29.                                 //Print out the first 15 values of array;
  30.                                 printf("The first 10 will make sense, the next 5 wont! \n");
  31.                                 for(i=0;i<15;i++){
  32.                                 printf("a[%d] = %0.3f \n",i,array[i]);
  33.                                 }
  34.                 }
  35.                
  36.                 leak(6);
  37.                
  38.                 //free the memory allocated
  39.                 free(array);

  40.                 return 0;
  41. }

  42. //Create basic function – passes the pointer to array (first position)
  43. void modify(double *array_diff){
  44.                 int i;
  45.                
  46.                 for(i=0;i<10;i++){
  47.                                 array_diff[i]=i/(i*i + 1);
  48.                 }
  49.                
  50.                 leak(4);
  51.                
  52.                 return;
  53. }              
  54.                
  55.                
  56. void leak(int size){
  57.                 char *p=0;
  58.                
  59.                 p = (char*)malloc(size);
  60.                
  61.                 return;
  62. }

复制代码
makefile:
  1. test:test.c leak_detector.h leak.so
  2.         gcc -o test test.c ./leak.so -rdynamic
  3. leak.so:leak_detector.o
  4.         gcc -shared -o leak.so leak_detector.o -rdynamic
  5. leak_detector.o:leak_detector.h leak_detector.c
  6.         gcc -fpic -c leak_detector.c -rdynamic
  7. clean:
  8.         rm *.o *.so
复制代码
文件说明:
leak_detector.h: 提供了实现malloc和free接口的头文件。
leak_detector.c: 实现了自定义的内存申请和释放的函数。
test.c:                用来测试自定义内存申请和释放的函数
leak_info.txt:     运行结果将会保存在这个文件中
makefile:           用来编译程序。

运行方法:
make leak.so     //生成 leak.so
make test        //生成可执行文件 test
./test              //运行test


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|猿媛之家    

GMT+8, 2021-2-16 18:46 , Processed in 0.396635 second(s), 31 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表