使用 Linux/GCC/C++,我想在调用 malloc/free/new/delete 时向 stderr 记录一些内容。我正在尝试了解库的内存分配,因此我想在运行单元测试时生成此输出。我使用 valgrind 进行内存泄漏检测,但我找不到一个选项来让它只是日志分配。
有任何想法吗?我正在寻找最简单的解决方案。重新编译库不是一种选择。
您可以使用 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所做的,它可能会做您想做的事情。
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.so ls 0x7ffc14931adc:malloc(5) = 0xb40010 0x7ffc1492c6b0:malloc(120) = 0xb40030 0x7ffc1497f61a:malloc(12) = 0xb40010 0x7ffc1492be38: malloc(776) = 0xb400b0 …
printf
可能会调用malloc
,这就是我们暂时撤消挂钩的原因。如果您malloc
以任何方式钩住,请注意这一点。
我自己没有对此进行过测试,但我很确定这些会起作用:
由于您不想重新编译库,因此提供有意义的输出(与仅“新调用 23 个字节”相比)可能需要获取堆栈跟踪。我记得使用函数来导航堆栈,但我现在找不到它们。也许调用 system() 和 pstack(1) 可以解决问题。
您可以重新定义 operator new 和 delete,并将这个新定义放在 std c++ 库之前。这可能无法捕获来自相关库正在使用的容器和标准组件的调用。这将需要重新链接。
使用可以使用 LD_PRELOAD 来动态改变操作符 new 和 delete。如果您的应用程序是动态链接的,则不需要重新链接。
希望这些指点有所帮助,对不起,我没有食谱。