4

Linux/GCC/C++ では、malloc/free/new/delete が呼び出されるたびに何かを stderr に記録したいと考えています。ライブラリのメモリ割り当てを理解しようとしているので、単体テストの実行中にこの出力を生成したいと思います。メモリ リークの検出に valgrind を使用していますが、割り当てだけをログに記録するオプションが見つかりません。

何か案は?可能な限り簡単な解決策を探しています。ライブラリの再コンパイルはオプションではありません。

4

4 に答える 4

15

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 のようなものを使用して独自のバージョンで呼び出しをオーバーライドする必要があります

于 2008-11-15T04:17:00.053 に答える
5

この記事(一番下までスクロール) では、C++ でグローバル演算子newと演算子をオーバーライドする方法について、非常に明確かつ簡潔に説明しています ( の例は示していませんが、概念は似ています)。deletenew[]

Linux と GCC で作業しているため、malloc と free をオーバーライドする限り、最も簡単な方法はmalloc_hookandを使用することfree_hookです。 これらの関数がどのように機能するかについての非常に良い説明があります

于 2008-11-15T04:05:34.180 に答える
4

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'
 (上記のコード)
EOF
$ cc -fPIC -shared -o mem.so mem.c
$ LD_PRELOAD=./mem.sols
0x7ffc14931adc: malloc(5) = 0xb40010
0x7ffc1492c6b0: malloc(120) = 0xb40030
0x7ffc1497f61a: malloc(12) = 0xb40010
0x7ffc1492be38: malloc(776) = 0xb400b0
…

printfを呼び出す可能性がmallocあるため、フックを一時的に元に戻します。malloc何らかの方法でフックする場合は、これに注意してください。

于 2009-11-14T20:48:11.280 に答える
1

私はこれを自分でテストしていませんが、これらがうまくいくと確信しています:

  • ライブラリを再コンパイルしたくないので、意味のある出力 (vs. 単に「23 バイトの新規呼び出し」) を提供するには、スタック トレースを取得する必要がある場合があります。関数を使用してスタックをナビゲートしたことを覚えていますが、今はそれらを見つけることができません。おそらく、system() と pstack(1) を呼び出すとうまくいくでしょう。

  • 演算子 new と delete を再定義して、この新しい定義を std c++ ライブラリの前に置くことができます。これは、問題のライブラリが使用しているコンテナおよび標準コンポーネントからの呼び出しをキャプチャしない場合があります。これには再リンクが必要です。

  • LD_PRELOAD を使用して、演算子 new と delete を動的に変更できます。アプリケーションが動的にリンクされている場合、再リンクは必要ありません。

これらのポインタがお役に立てば幸いです。レシピがなくて申し訳ありません。

于 2008-11-15T04:06:28.157 に答える