Linux 连接器支持一个很强大的技术,称为 库打桩(library interpositioning),它允许你截获对共享库函数的调用,取而代之执行自己的代码。使用打桩机制,你可以追踪对某个特殊库函数的调用次数,验证或追踪它的输入输出值,或者甚至把它替换成一个完全不同的实现。以下使用打桩机制来检测 C 程序是否存在内存泄漏。
编写包装函数打印 malloc 调用
—malloc.h—1
2
3
4
void *Malloc(size_t size);
void Free(void* ptr);
—Malloc.c—1
2
3
4
5
6
7
8
9
10
11
12
13
void* Malloc(size_t size) {
void* ptr = malloc(size);
printf("Malloc(%d)=%p\n", (int)size, ptr);
return ptr;
}
void Free(void* ptr) {
free(ptr);
printf("free(%p)\n", ptr);
}
编译时打桩
—int.c—1
2
3
4
5
6
7
int main() {
int* p = (int*) malloc(32);
free(p);
return 0;
}
1 | ➜ gcc -DTRACEHEAP -c Malloc.c |
运行程序会得到如下追踪信息:1
2
3➜ ./intc
Malloc(32) = 0x7f9fef402700
Free(0x7f9fef402700)
由于有 -I.
参数,所以会进行打桩。它告诉C预处理器在搜索通常的系统目录之前,先在当前目录中查找malloc.h
。
监测内存泄漏的思路
监测内存泄漏的关键是要能截获住对分配内存和释放内存的调用。截获住两个函数,我们就能跟踪每一块内存的生命周期。比如每成功分配一块内存后,把它的指针加入一个全局的 list
;每当释放一块内存,再把它的指针从list
中删除。当程序结束时,list
中剩余的指针就是指向那些没有被释放的内存。通过上述的打桩机制,我们可以实现内存泄漏的监测。
参考:- 《深入理解计算机系统》