【问题标题】:Outputting to stderr whenever malloc/free is called每当调用 malloc/free 时输出到 stderr
【发布时间】:2008-11-15 03:38:16
【问题描述】:

对于 Linux/GCC/C++,我想在调用 malloc/free/new/delete 时向 stderr 记录一些内容。我正在尝试了解库的内存分配,因此我想在运行单元测试时生成此输出。我使用 valgrind 进行内存泄漏检测,但我找不到一个选项来让它只是日志分配。

有什么想法吗?我正在寻找最简单的解决方案。重新编译库不是一种选择。

【问题讨论】:

    标签: c++ linux memory malloc valgrind


    【解决方案1】:

    您可以使用 ltrace 跟踪对 malloc/free 的调用:

    #include <stdlib.h>
    
    int main (void)
    {
      void *ptr = malloc(10);
      free(ptr);
    
      return 0;
    }
    
    
    $ g++ test.cpp -o test
    $ ltrace -e malloc,free ./test
    malloc(10)                                       = 0x804a008
    free(0x804a008)                                  = <void>
    +++ exited (status 0) +++
    

    要在不重新编译的情况下跟踪新/删除调用,您可能需要使用 LD_PRELOAD 之类的东西来用您自己的版本覆盖调用,这正是 LeakTracer 所做的,可能会满足您的需求。

    【讨论】:

      【解决方案2】:

      This article(向下滚动到底部)提供了关于如何在 C++ 中覆盖全局 newdelete 运算符的非常清晰和简洁的描述(请注意,它没有提供 new[] 的示例,但在概念上相似)。

      就覆盖 malloc 和 free 而言,由于您使用的是 Linux 和 GCC,因此最简单的方法是使用 malloc_hookfree_hookHere 很好地描述了这些功能的工作原理。

      【讨论】:

      • 这两种解决方案似乎都需要重新编译相关库。
      【解决方案3】:

      malloc_hook(3) 允许你全局设置你自己的malloc 函数。 (还有__realloc_hook__free_hook等,为了简单起见,我把它们省略了。)

      #include <stdio.h>
      #include <malloc.h>
      
      static void *(*old_malloc_hook)(size_t, const void *);
      
      static void *new_malloc_hook(size_t size, const void *caller) {
          void *mem;
      
          __malloc_hook = old_malloc_hook;
          mem = malloc(size);
          fprintf(stderr, "%p: malloc(%zu) = %p\n", caller, size, mem);
          __malloc_hook = new_malloc_hook;
      
          return mem;
      }
      
      static void init_my_hooks(void) {
          old_malloc_hook = __malloc_hook;
          __malloc_hook = new_malloc_hook;
      }
      
      void (*__malloc_initialize_hook)(void) = init_my_hooks;
      
      $ cat >mem.c (上面的代码) EOF $ cc -fPIC -shared -o mem.so mem.c $ LD_PRELOAD=./mem.so ls 0x7ffc14931adc:malloc(5) = 0xb40010 0x7ffc1492c6b0:malloc(120) = 0xb40030 0x7ffc1497f61a:malloc(12) = 0xb40010 0x7ffc1492be38: malloc(776) = 0xb400b0 …

      printf 可能会调用malloc,这就是我们暂时撤消挂钩的原因。如果您以任何方式钩住malloc,请注意这一点。

      【讨论】:

        【解决方案4】:

        我自己没有测试过,但我很确定这些会起作用:

        • 由于您不想重新编译库,因此提供有意义的输出(相对于“新调用 23 个字节”)可能需要获取堆栈跟踪。我记得使用函数来导航堆栈,但我现在找不到它们。也许调用 system() 和 pstack(1) 可以解决问题。

        • 您可以重新定义 operator new 和 delete,并将这个新定义放在 std c++ 库之前。这可能无法捕获来自相关库正在使用的容器和标准组件的调用。这需要重新链接。

        • 使用可以使用 LD_PRELOAD 来动态更改运算符 new 和 delete。如果您的应用程序是动态链接的,则不需要重新链接。

        希望这些指点有所帮助,很抱歉我没有食谱。

        【讨论】:

          猜你喜欢
          • 2023-04-07
          • 2014-05-21
          • 2015-08-20
          • 2010-11-06
          • 2012-04-15
          • 2012-06-10
          • 1970-01-01
          • 2011-02-28
          • 2011-11-28
          相关资源
          最近更新 更多