讲mtrace之前,我们先讲讲malloc hook。
malloc hook
顾名思义,malloc hook就是malloc的钩子函数。用户可以设置钩子函数,从而在用户使用malloc()或者realloc()申请内存,或者使用free()释放内存时会调用钩子函数。
glibc里面定义了如下钩子函数:
void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook)(void);
static void* (*__MALLOC_HOOK_VOLATILE __malloc_hook)(void *ptr, const void* caller);
static void (*__MALLOC_HOOK_VOLATILE __free_hook)(void *ptr, const void* caller);
__malloc_initialize_hook()指向的函数在程序启动时被调用,一般用于对钩子函数进行初始化。
__malloc_hook()指向的函数在调用malloc()时被调用。
__free_hook()指向的函数在调用free()时被调用。
应用程序如果要使用这个特性,首先需要定义一个钩子初始化函数,然后将这个函数地址赋值给__malloc_initialize_hook指针。这样当程序启动时,就会自动调用这个钩子初始化函数。我们可以在这个钩子初始化函数中,将自定义的钩子函数赋值给__malloc_hook和__free_hook。
基于这个特性,我们可以在钩子函数中对内存申请和释放进行统计。
mtrace
mtrace 就是基于malloc hook实现的一个内存诊断工具。使用者只需要在程序入口处调用mtrace()函数,从而在程序开始运行时就开启内存trace。mtrace()会将内存泄漏报告写到环境变量MALLOC_TRACE指向的一个可写的文件路径,然后我们使用mtrace工具来根据这个报告文件以及可执行程序的binary来生成一份可读的报告。
因为这个报告文件只有调用地址,所以需要用addr2line工具转化成代码行,所以编译代码时一定要带上-g,从而在binary中带上符号表。
使用步骤如下:
$ cat t_mtrace.c #include <mcheck.h> #include <stdlib.h> #include <stdio.h> int main(int argc, char *argv[]) { int j; mtrace(); for (j = 0; j < 2; j++) malloc(100); /* Never freed--a memory leak */ calloc(16, 16); /* Never freed--a memory leak */ exit(EXIT_SUCCESS); } $ cc -g t_mtrace.c -o t_mtrace $ export MALLOC_TRACE=/tmp/t $ ./t_mtrace $ mtrace ./t_mtrace $MALLOC_TRACE Memory not freed: ----------------- Address Size Caller 0x084c9378 0x64 at /home/cecilia/t_mtrace.c:12 0x084c93e0 0x64 at /home/cecilia/t_mtrace.c:12 0x084c9448 0x100 at /home/cecilia/t_mtrace.c:16