使用mtrace监控堆内存的分配与释放
应用程序中经常会使用malloc来分配堆内存,mtrace是glibc中提供的用于追踪堆内存分配与释放的功能。
头文件mcheck.h包含了mtrace()和muntrace()的声明。一旦使用了mecheck.h中声明的函数,编译器就会就将程序所使用的malloc()、realloc()、free()、memalign()函数,都会指向mtrace定义的malloc()、realloc()、free()、memalign()函数。调用mtrace()以后,这些函数会尝试将内存分配和释放的行为记录到MALLOC_TRACE环境变量所指定的文件中,并且调用被替换掉的分配、释放函数。如果MALLOC_TRACE环境变量没有被指定,或者指向的不是有效文件,那么mtrace()就不会有任何效果。调用muntrace()以后,也会停止记录内存分配、释放活动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <mcheck.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> #include "../common.h" void __mtracer_on() __attribute__((constructor)); void __mtracer_off() __attribute__((destructor)); void __mtracer_on() { char *p = getenv ( "MALLOC_TRACE" ); /* * Format of tracebuf is: * Filename prefix of maximum length of MAX_STR_LEN; * A DOT "."; * Process index with maximum length of MAX_IDX_LEN; */ char tracebuf[MAX_STR_LEN + sizeof ( char ) + MAX_IDX_LEN + 1]; if (!p) { p = "mtrace" ; } sprintf (tracebuf, "%." STRINGIFY(MAX_STR_LEN) "s.%." STRINGIFY(MAX_IDX_LEN) "d" , p, getpid()); setenv( "MALLOC_TRACE" , tracebuf, 1); atexit (&__mtracer_off); mtrace(); } void __mtracer_off() { muntrace(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #ifndef __COMMON_H__ #define __COMMON_H__ #define MAX_STR_LEN 31 #define MAX_IDX_LEN 5 /* * This is a technique to convert a number defined by macro into literal * string. * * For example: * STRINGIFY(MAX_STR_LEN) * turns into * "31" */ #define __STRINGIFY(x) #x #define STRINGIFY(x) __STRINGIFY(x) #endif /* __COMMON_H__ */ |
用gcc libmtrace.c -fPIC -shared -o libmtrace.so进行编译,产生libmtrace.so文件。
1 | LD_PRELOAD=. /libmtrace .so /bin/echo 42 |
用上面的命令调用echo程序,但是libmtrace会在echo的主函数开始运行之前,就调用mtrace()开始记录内存分配、释放活动。
然后可以使用一个叫做mtrace的Perl脚本小工具,分析产生的日志文件,找到所有没有释放的内存分配。
如果程序包含了编译信息,那么mtrace得到的结果就更详细,可以包含内存泄漏发生的源文件及行号信息。