tcmalloc是Google
Perftools中的一个组件,提供强大的内存池,比glibc的malloc快数倍;而且使用方便,只需添加链接选项-ltcmalloc即可。关于tcmalloc原理的分析已经有很多,这里就不重复了。本篇主要研究下tcmalloc是如何通过链接把new/delete/malloc/free等函数替换掉的
查了下相关资料,方法有3种:
方法1:使用环境变量LD_PRELOAD
环境变量LD_PRELOAD指定程序运行时优先加载的动态连接库,这个动态链接库中的符号优先级是最高的。标准C的各种函数都是存放在libc.so的文件中,在程序运行时自动链接。使用LD_PRELOAD后,自己编写的malloc的加载顺序高于glibc中的malloc,这样就实现了替换。
Hoard和TCMalloc的so版本就是这样实现的,陈皓也写过文章描述此方法的一些缺点
下面以strcmp为例来说明此方法
测试代码:
4 |
int main( int
argc, char **argv) |
6 |
char
passwd[] = "password" ; |
9 |
printf ( "Usage:
%s <password>\n" ,
argv[0]); |
13 |
if
(! strcmp (passwd,
argv[1])) |
15 |
printf ( "Correct
Password!\n" ); |
19 |
printf ( "Invalid
Password!\n" ); |
编译:
1 |
g++ checkpasswd.cpp -o checkpasswd |
运行:
结果:Correct Password!
so代码:
2 |
int
strcmp ( const
char *s1, const
char *s2) |
4 |
printf ( "hack
function invoked. s1=<%s>
s2=<%s>\n" , s1,
s2); |
编译:
1 |
g++ hack.cpp -shared -fPIC -o hack.so |
运行:
1 |
LD_PRELOAD= "./hack.so"
./checkpasswd abc |
结果变成了:
hack function invoked.
s1=<password>
s2=<abc>
Correct Password!
方法2 malloc调试变量
__malloc_hook是一组glibc提供的malloc调试变量中的一个,这组变量包括:
1 |
void
*(*__malloc_hook)( size_t
size, const void
*caller); |
2 |
void
*(*__realloc_hook)( void
*ptr, size_t size,
const void *caller); |
3 |
void
*(*__memalign_hook)( size_t
alignment, size_t size,
const void *caller); |
4 |
void (*__free_hook)( void
*ptr, const void
*caller); |
5 |
void
(*__malloc_initialize_hook)( void ); |
6 |
void
(*__after_morecore_hook)( void ); |
只要你在程序中写上"__malloc_hook =
my_malloc_hook;",之后的malloc调用都会使用my_malloc_hook函数,方便易行。但是这组调试变量不是线程安全的,当你想用系统malloc的时候不得不把他们改回来,多线程调用就得上锁了。因此方法2不很适用于系统内存优化,勉强用来简单管理线程内存使用。
详细用法请看这里;但要注意潜在的调用死循环,详情请看这里
tcmalloc的lib版本就是用的此方法,可以参看google-perftools-1.7版本src/tcmalloc.cc第348行:
http://taurus-ly.com/wp-content/uploads/image/2012/03/tcmalloc_hook.png
方法3 控制链接过程
ld中有一个选项
–wrap,当查找某个符号时,它优先先解析__wrap_symbol, 解析不到才去解析symbol。例如:
1 |
void *__wrap_malloc
( size_t c) |
3 |
printf
( "malloc called with %u\n" ,
c); |
4 |
return
__real_malloc (c); |
当其它文件与你实现__wrap_malloc函数的文件链接时使用–wrap malloc
,则所有到malloc的调用都是会链接到__wrap_malloc上。只有调用__reall_malloc时才会调用真正的malloc
4 |
extern "C" void
*__real_malloc( size_t ); |
5 |
extern "C" void
*__real_free( void
*); |
7 |
extern "C" void
*__wrap_malloc( size_t
c) |
9 |
printf ( "My
MALLOC called: %d\n" , c); |
10 |
return
__real_malloc(c); |
12 |
extern "C" void
*__wrap_free( void *ptr) |
14 |
printf ( "My
FREE called: 0xX\n" , ptr); |
15 |
return
__real_free(ptr); |
18 |
int main ( int
argc, char *argv[]) |
20 |
void
*ptr = malloc (12); |
编译:
g++ wrap.cpp -o wrap -Wl,-wrap,malloc,-wrap,free
结果:
My MALLOC called: 12
My FREE called: 0×00501010
- -Wl,option
- 把选项option传递给连接器.如果option中含有逗号,就在逗号处分割成多个选项.
参考:gcc手册http://www.shanghai.ws/gnu/gcc_2.htm
gcc -shared -Wl,-soname,your_soname \
-o library_name file_list
library_list
URL:http://taurus-ly.com/articles/2012/03/156.html
加载中,请稍候......