TCMalloc:如何在静态编译时覆盖我的malloc调用?

9
当我使用LD_PRELOAD=/usr/local/lib/libtcmalloc.so时,所有的malloc调用都变成了tcmalloc调用。然而,当我静态链接到libtcmalloc时,我发现除非我仍然使用LD_PRELOAD设置,否则直接使用malloc。那么我该如何以这样的方式静态编译tcmalloc,使我的malloc钩子进入tcmalloc呢?
注意:
- 我正在使用大量的C++ new等,因此仅仅将malloc定义为tcmalloc是行不通的。 - 可能我必须自己使用malloc_hook,但我认为我可以让tcmalloc为我做到这一点,因为在动态链接时它显然已经做到了。
2个回答

13

符号解析是以第一个匹配为基础的。您需要确保链接器在搜索libc.a之前搜索libtcmalloc.a。我假设您没有显式地链接libc.a,因为通常不需要这样做。解决方案是指定-nostdlibs,然后以您想要搜索它们的顺序显式地链接所有必要的库。通常会像这样:

-nostdlibs -llibtcmalloc -llibm -llibc -llibgcc

另一个可能更简单的解决方案是链接所需的目标文件以解决tcmalloc,而不是静态库,因为目标文件在解析符号时优先于库。


2
TCMalloc覆盖了所有分配/释放函数调用,包括所有变体的New/Delete和C API(malloc/free/calloc/realloc/valloc/pvalloc/mem_aligned/malloc_usable_size)。 对于基于gcc的平台,它使用别名指令实现覆盖。
“我正在大量使用C++ new等,所以仅将malloc定义为tcmalloc不起作用。”
在TCMalloc头文件中,malloc已经被别名为tc_malloc,因此这没有任何效果。例如:
#define ALIAS(tc_fn)   __attribute__ ((alias (#tc_fn), used))
void* malloc(size_t size) __THROW               ALIAS(tc_malloc)

关于New,请注意,与glibc和其他实现(Windows)不同的是,tcmalloc的New没有调用malloc。
TCMalloc的New被别名为tc_newtc_newarray,它们将调用TCMalloc的“神奇”内存管理器,并且在某些情况下,与libc malloc一样,将启动sbrk/brk系统调用。
另一件需要做的事情是确保gcc不链接libc的malloc变体。为此,请在Makefile中的C++标志中添加以下内容:
-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free

另外,不要忘记指定TCMalloc静态库:

LIB_TCMALLOC = $(TCMALLOC_LIB_DIR)/libtcmalloc_minimal.a
LIB_DIR := .... -L$(TCMALLOC_LIB_DIR) ...
LIBS := ... -static $(LIB_TCMALLOC) ...

可能我需要自己使用malloc_hook,但我本以为我可以让tcmalloc为我完成这个操作,因为在动态链接时,它显然已经这样做了。
TCMalloc不使用malloc_hooks,因为现在认为由于线程安全问题而被弃用。它只是利用内存分配方法是弱符号的事实。它通过别名(在gcc中)__attribute__((alias))或函数调用覆盖这些符号。
请参考: https://github.com/gperftools/gperftools/blob/master/README

动态链接libtcmalloc似乎无法与-fno-builtin-malloc、-fno-builtin-calloc、-fno-builtin-realloc和-fno-builtin-free一起工作。在链接LDD后,libtcmalloc.so并不会列为共享对象依赖项之一。@daniel Helper能否详细说明一下为什么这样不起作用? - anaken78
如果tcmalloc头文件将malloc声明为tc_malloc的别名,那么它是否会与标准C++头文件中的另一个malloc声明发生冲突? - doraemon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接