CatCoding

内存泄漏

2010-12-22

以前写的一些程序运行一段时间后占用的内存越来越多,估计是内存泄露了。服务端的程序要长时间的运行,内存泄露是个很严重的问题。于是再检查程序,很崩溃的是还有另外一个模块不是自己写的,看起来很麻烦。看了半小时后发现一些问题,但是还是不能保证是否完全解决了。同事让我用以前他们写的一些函数,对应的为 MALLOC 和 FREE。仔细看了一下觉得很不错,其实就是把 malloc 和 free 函数封装了一下,用来记录申请空间的文件和代码位置,使用方法就是用 MALLOC 和 FREE 替代原来的函数。主要的数据结构是:

typedef struct
{
    long pcode;                          //指针
    char filename[128];                  //申请空间的源文件名称
    int line;              //申请空间的代码所在的行
    int ct;                   //内存状态:0-未闭合,1-闭合,2-log/脚手架
}mem_info;

mem_info mem_in[MEM_SIZE];  //MEM_SIZE 最大指针数目
int mem_in_id; //数组中已经占有的 mem_info 数目
int mem_check_statue; //是否进行内存泄露检查

然后有两个函数,一个是初始化函数 mem_check_init(),另一个为 mem_check_write(),这样就能检查者两个函数之间的代码是否有内存泄露,mem_check_write() 可以打印成一个表,所有申请了空间的代码的文件名称和代码所在的行数,以及运行到 mem_check_write() 这里的时候所有申请空间的状态,1 表示已经释放,0 表示申请未释放,2 表示的是脚手架的位置(用来方便检查哪一小段代码是否有内存泄露)。

#define MALLOC(size)  ck_malloc(size,FILE__,LINE) //FILE 文件 LINE 代码所在行

void   __ck_malloc(int size,char file,int line)
{
    void p=malloc(size);

    if (mem_check_statue)    return p;
    if (mem_in_id>=MEM_SIZE) return p;

    mem_in[mem_in_id].pcode=(long)p;
    strcpy(mem_in[mem_in_id].filename,file);
    mem_in[mem_in_id].line=line;
    mem_in[mem_in_id].ct=0; // 状态:0-未闭合
    mem_in_id++;

    return p;
}

那么 FREE(p),进行的操作就是现在数组中找到是否有这个 p,如果有就改变状态,变为 1 表示闭合了,也就是释放掉了。CALLOC 和 MALLOC 类似,是调用 calloc,函数 malloc() 和函数 calloc() 的主要区别是前者不能初始化所分配的内存空间,而后者能。REALLOC 有点不一样,调用 void* np=realloc(p,size),这里要注意 np 和原来的 p 有可能不一样,有可能一样,比较一下进行相应处理。最后 mem_check_write() 遍历上上面的数组打印出来表,其顺序就是按照代码执行的顺序了,其中脚手架可以比较方便的定位于申请了没有释放的代码行,也就是查找两个 2 之间的 0 所对应的行。

这是一个很不错的方法,今天用这个办法找到了好多处不易发现的内存泄露错误。但这也有其缺点,即使完全通过也不能保证就完全没内存泄露了,除非测试时运行代码的覆盖率要保证所有代码都运行到了,这也是正规的、高质量的测试所要做到的程度。我们现在没有时间来做足够好的测试,以后再好好规范一下。

公号同步更新,欢迎关注👻