主要介绍利用library injection方法检测内存泄露.
library injection就是重载库里面对应的函数,让程序调用library里的函数,而不是调用库函数里的函数.
内存泄露主要是重载malloc和free函数,重载后,程序中调用malloc和free分配和释放内存时,就是利用自己编写的malloc和free函数.
1.library injection如何完成?
在linux环境下,可以利用LD_PRELOAD来指定编译好的重载库.
具体的方法如下:
1) g++ -shared -fPIC leakfinder.cpp -o leakfinder.so -ldl //编译得到重载malloc和free函数的动态库
2) export LD_PRELOAD=./leakfinder.so //设定预先加载的动态库
3) ./c_example //执行例子程序
其中,重载malloc和free函数时,需要利用extern "C"来标识malloc和free函数.这是由于C++和C对函数的命名不致,C++中函数命名包含对应的参数,而C语言不包括.
2.重载的malloc和free函数如何实现,需要完成那些工作?
1) 基本的内存分配和释放工作必须完成,可以调用系统本身的malloc和free函数完成.
利用void* dlsym(void* handle,const char* symbol)函数获取系统内的malloc和free函数指针,利用系统的malloc和free函数指针完成内存分配和释放的基本工作.
2) 保存内存分配的信息,便于检测最后是否存在内存泄露,利用vector来保存对应内存分配信息.
每次分配时,则添加一个记录信息到vector中,每次释放时,则从中搜寻对应的记录信息删除.
最后程序结果时,检测vector是否存在记录信息来判断是否发生内存泄露.
3) 内存分配信息的记录,包括分配的地址,利用函数调用顺序(便于内存泄露时,给出提示信息)
其中,在linux环境下,函数调用栈的信息通过backtrace和backtrace_symbols来获得.
4) 程序结束时,检测是否存在内存泄露,若存在,输出相应的信息.利用__attribute__(destructor)来指定程序结束后,执行的内存泄露统计信息.
static void compile_allocation() __attribute__((destructor));
5) 保存内存分配信息时,需要分配和释放内存,若不与外界的内存分配和释放进行区分,将会出现无限循环递归调用.
利用全局标记量来标识是从外部的调用,还是从内部的调用
6) 全局的标记量可能被多线程修改,导致出现线程不安全问题.因而需要利用互斥锁对内存信息保存进行控制.
参考文献:http://www.codeproject.com/Articles/393957/Cplusplus-Memory-Leak-Finder