自实现简单的c内存泄漏检测工具

成熟的内存泄漏检测工具很多,比如:
valgrind  https://www.valgrind.org/
mtrace https://man7.org/linux/man-pages/man3/mtrace.3.html (glibc内置)
memwatch https://www.linkdata.se/sourcecode/memwatch/
dlmalloc 一种内存分配器,比如android中 bionic c库使用dlmalloc 来分配内存
leakTracer http://www.andreasen.org/LeakTracer/
基本上原理都是两种情况:
一种是对申请内存的系统函数malloc free 重写/宏定义替换/注册hook等手段,达到每次执行 malloc free等函数是都做一个记录,最后通过记录来查看分析是否内存没有释放,重复释放,溢出等等问题。 这种方式需要在编译前对我们的代码进行改动,编译出来的文件就已经具备这些检测功能,比如上面的 mtrace memwatch dlmalloc 等。
另一种方式,不需要对原执行文件或库进行改动,而是虚拟出一个假的运行环境,这个环境中提供系统的这些功能,把我们可执行文件放到这个环境中运行,其运行的过程都被这个虚拟环境所记录,利用这个虚拟环境的记录来分析内存使用情况。比如valgrind
以上都是动态的检测,即监控记录程序运行的过程,也可以静态检测,就是通过一个语法从代码层面文字分析。
这里用第一种原理,类似于memwatch,简单实现一个malloc free的检测模块,当然实际的开发中会使用以上成熟的检测工具,这里做这么一个小工具,主要是探究其原理,毕竟这些成熟的检测工具,也不是生来就有的,也是前辈们一行行代码垒起来的。

=========================================================================

分割线

=========================================================================
主要原理
用宏定义对malloc free进行一层包装,在里面维护一个列表(这里对应一个全局的大数组),记录每一次的 malloc和free调用
实际效果:

 

//canok 20210619
#ifndef D_MALLOC_H
#define D_MALLOC_H

#define DMALLOC_ENABLE 1
void *D_malloc(size_t size,const char *file, int line);
void *D_calloc(size_t nmemb, size_t size,const char *file, int line);
void *D_realloc(void *ptr, size_t size,const char *file, int line);
void D_free(void *pMemory, const char *file, int line);

#if DMALLOC_ENABLE
#define D_Malloc(size) D_malloc(size,__FILE__,__LINE__)
#define D_Calloc(nmeb,size) D_calloc(nmeb,size,__FILE__,__LINE__)
#define D_Realloc(ptr,size) D_realloc(ptr,size,__FILE__,__LINE__)
#define D_Free(pMemory) D_free(pMemory,__FILE__,__LINE__)
#else
#define D_Malloc(size) malloc(size)   
#define D_Calloc(nmeb,size) calloc(nmeb,size)   
#define D_Realloc(ptr,size) realloc(ptr,size) 
#define D_Free(pMemory) free(pMemory)  
#endif


void Debug_malloc_start();
void Debug_malloc_stop();
#endif
//canok 20210619
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include "D_malloc.h"

typedef struct _s_malloc_type{
  const void   *pointer;
  unsigned int  bytes;
  const char   *file;
  unsigned int  line;
}DMallocType;

#define INFO_SIZE 1024*10
#define SIZE_OF_MEM_DEBUG_ARRAY 1000
#define ALOG(x...) printf("[%s %s %d]:",__FILE__,__FUNCTION__,__LINE__);printf(x)


static DMallocType MallocTable[SIZE_OF_MEM_DEBUG_ARRAY] = {0};
static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
static int gStart =0;
static char *gInfo=NULL;
static void MM_MallocAddEntry(const void *pMemory,unsigned int size,const char *file,unsigned int line){
  int i=0;
  if( pMemory != NULL ){
    for( i = 0; i < SIZE_OF_MEM_DEBUG_ARRAY; i++ ){
      if( MallocTable[i].pointer == NULL ){
        MallocTable[i].pointer = pMemory;
        MallocTable[i].bytes   = size;
        MallocTable[i].file    = file;
        MallocTable[i].line    = line;
        break;
      }
    }

    if( i >= SIZE_OF_MEM_DEBUG_ARRAY ){
      ALOG("VIDEO_Memory Unable to store malloc info: [%s:%d] %d bytes\n",file, line, size );
    }
  }
}

static DMallocType* MM_MallocFindEntry(const void *pMemory){
  unsigned int i=0;
  if( pMemory != NULL ){
    for( i = 0; i < SIZE_OF_MEM_DEBUG_ARRAY; i++ ){
      if( MallocTable[i].pointer == pMemory ){
        return &MallocTable[i];
      }
    }
  }
  return NULL;
}

static void MM_MallocDeleteEntry(DMallocType *pEntry){
  if( pEntry != NULL ){
    memset( pEntry, 0, sizeof(*pEntry) );
  }
}
static void checkTable(){
    int i=0;
    for( i = 0; i < SIZE_OF_MEM_DEBUG_ARRAY; i++ ){
      if( MallocTable[i].pointer !=NULL ){
             sprintf(gInfo,"%s not free ptr=%p , %d bytes at: %s:%d\n",gInfo,MallocTable[i].pointer,MallocTable[i].bytes,MallocTable[i].file,MallocTable[i].line);
             //snprintf(gInfo,INFO_SIZE,"%s not free ptr=%p , %d bytes at: %s:%d",gInfo,MallocTable[i].pointer,MallocTable[i].bytes,MallocTable[i].file,MallocTable[i].line);
      }
    }
}

void *D_malloc(size_t size,const char *file, int line){
    void *pMemory = NULL;
    pthread_mutex_lock(&gMutex);
    do{
        pMemory = malloc(size);
        if(gStart && pMemory){
            //be careful, May be AddEntry failded
            MM_MallocAddEntry(pMemory,size,file,line);
        }
    }while(0);
    pthread_mutex_unlock(&gMutex);
    return pMemory;
}

void * D_calloc(size_t nElem, size_t elSize, const char *file, int line){
    void *pMemory = NULL;
    pthread_mutex_lock(&gMutex);
    do{
        pMemory = calloc(nElem,elSize);
        if(gStart && pMemory){
            //be careful, May be AddEntry failded
            MM_MallocAddEntry(pMemory,elSize*nElem,file,line);
        }
    }while(0);
    pthread_mutex_unlock(&gMutex);
    return pMemory;
}

void * D_realloc(void *pOldMemory , size_t size, const char *file, int line){
    void *pMemory = NULL;
    pthread_mutex_lock(&gMutex);
    do{
        if(gStart){
            DMallocType *pEntry=NULL;
            pEntry = MM_MallocFindEntry(pOldMemory);
            if(NULL == pEntry){
                ALOG("findEntyr erro[%s:%d] ptr=%p, %lu bytes",file, line, pOldMemory, size);
                break;
            }
            pMemory = realloc(pOldMemory,size);
            if(pMemory){
                //be careful, May be AddEntry failded
              MM_MallocDeleteEntry(pEntry);
              MM_MallocAddEntry(pMemory,size,file,line);
            }
        }else{
            pMemory = realloc(pOldMemory,size);
        }
    }while(0);
    pthread_mutex_unlock(&gMutex);
    return pMemory;
}


void D_free(void *pMemory, const char *file, int line){
    DMallocType *pEntry=NULL;
    pthread_mutex_lock(&gMutex);
    do{
        if(gStart){
            pEntry = MM_MallocFindEntry(pMemory);
            if(NULL == pEntry){
                sprintf(gInfo,"%s free invalue ptr:=%p at %s:%d\n",gInfo,pMemory,file,line);
                //snprintf(gInfo,INFO_SIZE,"%s free invalue ptr:=%p at %s:%d\n",gInfo,pMemory,file,line);
                break;
            }else{
                MM_MallocDeleteEntry(pEntry);
                free(pMemory);
            }
        }else{
            free(pMemory);
        }
    }while(0);
    pthread_mutex_unlock(&gMutex);
    /* Error checking */
}

void Debug_malloc_start(){
    pthread_mutex_lock(&gMutex);
    do{
        if(gStart){
            break;
        }
        gInfo = (char *)malloc(INFO_SIZE);
        if(gInfo==NULL){
            ALOG("[%s%d] start failed, malloc err",__FUNCTION__,__LINE__);
            break;
        }
        gStart=1;
    }while(0);
    pthread_mutex_unlock(&gMutex);
}
void Debug_malloc_stop(){
    pthread_mutex_lock(&gMutex);
    do{
        if(!gStart){
            break;
        }
        gStart=0;
        checkTable();
        FILE*fpout = fopen("loginfo","w+");
        if(fpout!=NULL){
            fwrite(gInfo,1,INFO_SIZE,fpout);
            fclose(fpout);
        }
        ALOG("the memory info:\n%s",gInfo);
        free(gInfo);
    }while(0);
    pthread_mutex_unlock(&gMutex);
}

int main(){
    printf("hello world!\n");
    Debug_malloc_start();
    char *m1 = D_Malloc(128);
    char *m2 = D_Malloc(129);
    char *m3 = D_Calloc(50,2);
    char *m4 = D_Realloc(m2,200);
    char *m5=NULL;
    D_Free(m5);
    Debug_malloc_stop();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值