内存泄漏检测利器:使用LD_PRELOAD加载你的malloc库

使用C或者C++开发程序的同学肯定有过类似的经历,当程序发生内存泄漏时,如果运气好,很快能够找到代码出错的地方,但是如果代码庞大,定位起来将是一个非常头疼的问题。
这里我给出一个方法可以帮助你快速定位出内存泄漏的地方,而且这个方法不需要修改你原有的代码。大概的原理如下:
1、使用封装的方式实现你自己的malloc, realloc, free, calloc等内存管理函数。
2、在内存申请封装函数里记录申请的地址以及调用栈(可以使用unwind库)。
3、在内存释放封装函数里先查询该地址是否被记录,如果是则将之前的记录销账掉。
4、使用LD_PRELOAD环境变量提前加载你的封装库,开始运行你的程序。
5、经过一段时间后,如果产生了内存泄漏现象,上面未销账的记录即有可能是内存泄漏点,打印相应的堆栈就可知道出问题的代码。

这里简单演示一下封装malloc函数的示例代码:

  • mwrap.c
#define _GNU_SOURCE
#include 
#include 
#include 
#include 

static void* (*real_malloc)(size_t)         = NULL;

static void init()
{
    real_malloc  = dlsym(RTLD_NEXT, "malloc");
    if (!real_malloc) {
        fprintf(stderr, "unable to get malloc symbol!\n");
        exit(1);
    }
    fprintf(stderr, "mwrap.so: successfully wrapped!\n");
}

void *malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }
    void *ret = real_malloc(size);
    fprintf(stderr, "using wrapped malloc: size = %ld, pointer = %p\n", size, ret); // 如果打印,一定要用fprintf(stderr),否则会产生无限循环,因为fprintf(stdout)也会使用malloc!

    return ret;
}

$ gcc -fPIC -shared -o mwrap.so mwrap.c -ldl

  • 测试程序:test_wrap.cpp
#include 

class MyClass {
public:
    MyClass() {p = new char[1024];}
    ~MyClass() {if (!p) delete []p;}
private:
    char* p;
};


int main()
{
    char* p = (char*)malloc(16);
    free(p);

    MyClass myObj;

    return 0;
}

$ g++ -o test_wrap test_wrap.cpp

  • 测试
hank@hank-ThinkPad-T450s:~/cpp/test_preload$ LD_PRELOAD=./mwrap.so ./test_wrap
mwrap.so: successfully wrapped!
using wrapped malloc: size = 72704, pointer = 0x559481454260
using wrapped malloc: size = 16, pointer = 0x559481465e70
using wrapped malloc: size = 1024, pointer = 0x559481465e90

可以看到test_wrap代码中无论是使用new还是直接使用malloc的代码都会调用封装后的malloc库,这时候你就可以在封装的函数里记录你想要的信息了。

你可能感兴趣的:(内存泄漏检测利器:使用LD_PRELOAD加载你的malloc库)