使用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()以后,也会停止记录内存分配、释放活动。
#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(); }
#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文件。
LD_PRELOAD=./libmtrace.so /bin/echo 42
用上面的命令调用echo程序,但是libmtrace会在echo的主函数开始运行之前,就调用mtrace()开始记录内存分配、释放活动。
然后可以使用一个叫做mtrace的Perl脚本小工具,分析产生的日志文件,找到所有没有释放的内存分配。
如果程序包含了编译信息,那么mtrace得到的结果就更详细,可以包含内存泄漏发生的源文件及行号信息。