您的位置:首页 > 运维架构 > Linux

在应用程序中替换Linux中Glibc的malloc的四种方法

2016-03-15 20:25 399 查看
转自:http://www.xuebuyuan.com/2223733.html

打算优化系统的内存分配,接管

glibc

提供的内存管理,但是整个工程的代码量很大,使用

malloc



realloc



calloc



free

的地方到处都是,如果自己写好的接口需要重命名所有的调用,先不说工作量,部分没有权限查看代码的

.a

文件就搞不定了。所以需要替换掉系统的

malloc

,保证原有调用的名称不变。经过尝试,共有四种方法可以替换,各有优缺点吧。
方案

1

使用环境变量

LD_PRELOAD


        

环境变量

LD_PRELOAD

指定程序运行时优先加载的动态连接库,这个动态链接库中的符号优先级是最高的。标准

C

的各种函数都是存放在

libc.so.6

的文件中,在程序运行时自动链接。使用

LD_PRELOAD

后,自己编写的

malloc

的加载顺序高于

glibc

中的

malloc

,这样就实现了替换。用法:

        

[littlefang]$

LD_PRELOAD=" ./mymalloc.so"

        

这是最实用的替换方法,动态链接库加载过程中提供了初始化函数,可以轻易的获得系统

malloc

的句柄,再将它做进一步的管理,

Hoard

(参见
深入

Linux

的内存管理,关于

PTMalloc3



Hoard



TCMalloc

)的就是这样实现的。

方案

2  

malloc

调试变量


        

__malloc_hook

是一组

glibc

提供的

malloc

调试变量中的一个,这组变量包括:

view plain
copy to clipboard
print
?

void

 *(*__malloc_hook)(

size_t

 size, 

const

 

void

 *caller);   

  
void

 *(*__realloc_hook)(

void

 *ptr, 

size_t

 size, 

const

 

void

 *caller);   

  
void

 *(*__memalign_hook)(

size_t

 alignment, 

size_t

 size, 

const

 

void

 *caller);   

  
void

 (*__free_hook)(

void

 *ptr, 

const

 

void

 *caller);   

  
void

 (*__malloc_initialize_hook)(

void

);   

  
void

 (*__after_morecore_hook)(

void

);  

 

只要你在程序中写上

”__malloc_hook

= my_malloc_hook;”

,之后的

malloc

调用都会使用

my_malloc_hook

函数,方便易行。但是这组调试变量不是线程安全的,当你想用系统

malloc

的时候不得不把他们改回来,多线程调用就得上锁了。因此方案

2

不很适用于系统内存优化,勉强用来简单管理线程内存使用。

        

详细用法请猛击这里

方案

3

编译自己的

libmalloc.a


        

关于重载

glibc



malloc

库,

ChinaUnix

上有这样的讨论



如果我用

cc -o myprog

myprog.c -lmylib



而不想修改缺省的

ld

的命令行参数或者

linker

脚本,不知可不可以?

这个方法确实比较理想,只需要

make

一次就

OK

了,不用更改环境变量,省得担心后台运行的问题。后面有人回复让楼主试试,不知道楼主试了没有,我试了一下。

若要把系统内存管理起来,首先还是要向操作系统申请内存,这个问题对于

LD_PRELOAD

方案很简单,链接库加载时就可以把

glibc

中的

malloc

加载进来,以后直接调用就可以了,如:

real_malloc =

dlsym(RTLD_NEXT, "malloc");

但是你如果使用自己编译的

malloc

库,在你调用

dlsym

这个函数时,

dlsym

会调用

dlerror



dlerror

会调用

calloc



calloc

要调用

malloc

,而你的

malloc

正在初始化等待

dlsym

返回中,于是死循环了。有人说,在调用没有初始化完毕的

malloc

时,返回

NULL

,我试了

dlsym

不认账,加载可耻的失败了。在满世界的寻找

dlsym

的替代品未果后,我把目光瞄住了

tcmalloc

(参见
深入

Linux

的内存管理,关于

PTMalloc3



Hoard



TCMalloc

)。

Tcmalloc

使用时需要在链接时加上

-ltcmalloc

即可,它代码里也没使用

dlsym

,大略了看了下它的代码,它使用

mmap

从系统获取的内存。

void *mmap(void

*addr, size_t len, int prot, int flags, int fildes, off_t off);

这种方法从页面级就要对系统内存进行管理,

Glibc

中的

malloc

就是使用

mmap



brk

两个函数从程序堆中获得内存的。无疑,这比起用

malloc

分配的内存复杂了很多。

方案

4

链接过程控制


ld

中有一个选项

–wrap

,当查找某个符号时,它优先先解析

__wrap_symbol,

 解析不到才去解析

symbol

。例如:

view plain
copy to clipboard
print
?

void

 *__wrap_malloc (

size_t

 c)  

  
{  
  
     printf ("malloc called with %zu/n"

, c);  

  
     return

 __real_malloc (c);  

  
}  

 

当其它文件与你实现

__wrap_malloc

函数的文件链接时使用

--wrap

malloc

,则所有到

malloc

的调用都是会链接到

__wrap_malloc

上。只有调用

__reall_malloc

时才会调用真正的

malloc



view plain
copy to clipboard
print
?

#include <stdio.h>

  

  
#include <stdlib.h>

  

  
   
  
void

 *__real_malloc(

size_t

);  

  
   
  
void

 *__wrap_malloc(

size_t

 c)  

  
{  
  
        printf("My MALLOC called: %d/n"

, c);  

  
        return

 __real_malloc(c);  

  
}  
  
   
  
int

 main (

int

 argc, 

char

 *argv[])  

  
{  
  
        void

 *ptr = malloc(12);  

  
   
  
        return

 0;  

  
}  

 

编译 

[littlefang]$

gcc wrap.c -o wrap -Wl,-wrap,malloc

运行 

[littlefang]$

./wrap

My MALLOC

called: 12

Gcc



g++

编译使用

–Wl

选项,以指定链接器参数,比如同时替换

malloc,free



realloc

就要用

gcc wrap.c -o wrap -Wl,-wrap,malloc  

-Wl,-wrap,free  

-Wl,-wrap,realloc



特别需要注意的是,如果你的

__wrap_malloc是用

C++

实现的,千万不要忘记加上

extern

“C”

做修饰,不然会出现"undefine reference to __wrap_malloc"。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: