【问题标题】:GLIBC: debugging memory leaks: how to interpret output of mtrace()GLIBC:调试内存泄漏:如何解释 mtrace() 的输出
【发布时间】:2010-09-14 07:32:48
【问题描述】:

我正在尝试调试内存泄漏问题。我正在使用 mtrace() 来获取 malloc/free/realloc 跟踪。我已经运行了我的 prog,现在有一个巨大的日志文件。到目前为止,一切都很好。但我在解释文件时遇到问题。看看这些行:

@ /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 重复。但是怎么会这样呢?

【问题讨论】:

    标签: c memory-leaks glibc mtrace


    【解决方案1】:

    一种可能的解释是同一个函数分配不同的缓冲区大小? strdup 就是一个这样的例子。

    对于第二个问题,运行时可能正在分配一些“静态”暂存区域,这些暂存区域在进程终止之前不会被释放。到那时,无论如何,操作系统都会在该过程之后进行清理。

    这样想:在 Java 中,没有析构函数,也不能保证任何对象都会调用终结。

    【讨论】:

    • 这不仅仅是一个函数多次调用malloc(),实际上是一次调用malloc/realloc/calloc,因为返回地址相同。如果运行时正在分配暂存区,为什么它会返回指向 this are 的指针作为第二个 malloc() 的结果?
    【解决方案2】:

    尝试在 valgrind 下运行您的应用。它可能会让您更好地了解实际泄露的内容。

    【讨论】:

    • 我的经验是:valgrind不喜欢java。它很容易崩溃。
    【解决方案3】:

    您正在查看 mtrace 的直接输出,这非常令人困惑和违反直觉。幸运的是,有一个 perl 脚本(称为 mtrace,可在 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
    

    输出应该很多更容易消化。

    【讨论】:

    • 我已经检查了这个脚本。它会给我和我的脚本一样的输出:Alloc X duplicate。
    【解决方案4】:

    分配内存的函数被多次调用。调用者地址指向执行分配的代码,并且该代码只是运行了多次。

    这是一个 C 语言示例:

    void *allocate (void)
    {
      return (malloc(1000));
    }
    
    int main()
    {
      mtrace();
      allocate();
      allocate();
    }
    

    mtrace 的输出是:

    内存未释放: ----------------- 地址大小调用者 0x0000000000601460 0x3e8 在 0x4004f6 0x0000000000601850 0x3e8 在 0x4004f6

    注意调用者地址如何相同?这就是为什么 mtrace 分析脚本说它们是相同的,因为同一个 bug 被多次看到,导致多次内存泄漏。

    如果可以的话,使用调试标志 (-g) 进行编译会很有帮助:

    内存未释放: ----------------- 地址大小调用者 0x0000000000601460 0x3e8 在 /home/andrjohn/development/playground/test.c:6 0x0000000000601850 0x3e8 在 /home/andrjohn/development/playground/test.c:6

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-09-29
      • 1970-01-01
      • 1970-01-01
      • 2010-12-01
      • 1970-01-01
      • 2011-12-08
      • 1970-01-01
      • 2021-01-10
      相关资源
      最近更新 更多