GLIBC:调试内存泄漏:如何解释mtrace()的输出
我正在尝试调试内存泄漏问题。我正在使用mtrace()获得malloc / free / realloc跟踪。我跑了我的编,现在有一个巨大的日志文件。到目前为止,一切都很好。但是我在解释文件时遇到了问题。看一下这些行:
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x1502570 0x68 @ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x1502620 0x30 @ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x2aaab43a1700 0xa80 @ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x1501460 0xa64
奇怪的是,一个呼叫(相同的返回地址)负责4个分配。
甚至陌生人:
@ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x2aaab43a1700 0xa2c … @ /usr/java/ibm-java2-x86_64-50/jre/bin/libj9prt23.so:[0x2b270a384a34] + 0x2aaab43a1700 0xa80
在这两行之间,永远不会释放块0x2aaab43a1700。
有人知道如何解释吗?一个电话怎么会导致4个分配?以及malloc如何返回先前已分配的地址?
编辑2008/09/30:
分析GLIBC(mtrace.pl)提供的mtrace()输出的脚本在这里没有任何帮助。它只会说:Alloc 0x2aaab43a1700复制。但是,这怎么可能呢?
解决方案
一种可能的解释是,同一函数分配不同的缓冲区大小吗?这样的例子之一就是strdup。
对于第二个问题,运行时可能会分配一些"静态"暂存区,该暂存区在进程终止之前是不希望释放的。到那时,无论如何,操作系统将在清理之后进行清理。
这样考虑:在Java中,没有析构函数,也不能保证对任何对象都将调用终结方法。
尝试在valgrind下运行应用程序。它可以使我们更好地了解实际泄漏的内容。
我们正在看mtrace的直接输出,这是非常令人困惑和违反直觉的。幸运的是,有一个perl脚本(称为gtrace,在glibc-utils中找到),可以非常轻松地帮助解析此输出。
编译并调试,然后运行mtrace,如下所示:
$ gcc -g -o test test.c $ MALLOC_TRACE=mtrace.out ./test $ mtrace test mtrace.out Memory not freed: ----------------- Address Size Caller 0x094d9378 0x400 at test.c:6
输出应该更容易消化。
分配内存的函数被多次调用。调用者地址指向进行分配的代码,并且该代码仅运行了不止一次。
这是C语言中的一个示例:
void *allocate (void) { return (malloc(1000)); } int main() { mtrace(); allocate(); allocate(); }
mtrace的输出是:
Memory not freed: ----------------- Address Size Caller 0x0000000000601460 0x3e8 at 0x4004f6 0x0000000000601850 0x3e8 at 0x4004f6
请注意,呼叫者地址如何相同?这就是mtrace分析脚本说它们相同的原因,因为同一错误被查看一次以上,从而导致多次内存泄漏。
如果可以,使用调试标志(-g)进行编译将很有帮助:
Memory not freed: ----------------- Address Size Caller 0x0000000000601460 0x3e8 at /home/andrjohn/development/playground/test.c:6 0x0000000000601850 0x3e8 at /home/andrjohn/development/playground/test.c:6