打算优化系统的内存分配,接管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调试变量中的一个,这组变量包括:

[cpp:nogutter] view plaincopyprint?

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。例如:

[cpp:nogutter] view plaincopyprint?

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。

[cpp:nogutter] view plaincopyprint?

#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"。

转载于:https://www.cnblogs.com/li-hao/archive/2013/04/02/2995273.html

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

  1. linux如何创建共享内存,linux实现共享内存同步的四种方法

    https://blog.csdn.net/sunxiaopengsun/article/details/79869115 本文主要对实现共享内存同步的四种方法进行了介绍. 共享内存是一种最为高效的进 ...

  2. Linux开机自动化执行脚本的四种方法(真实案例分享)

    Linux开机自动化执行脚本的四种方法(真实案例分享) 最近眼睛有点疼,可能是长时间面对电脑屏幕的原因罢.百度后安装了Redshift这款护眼工具,只要事先写好配置文件它会根据你的地理位置自动调节屏幕 ...

  3. linux下查看mysql版本的四种方法

    Linux查看MySQL版本的四种方法 1 在终端下执行 mysql -V 2 在help中查找 mysql --help |grep Distrib 3 在mysql 里查看 select vers ...

  4. linux在终端找文件,在Linux Shell上查找文件的四种方法

    众所周知,Linux是极客和开发人员最常使用的操作系统,他们大多是键盘手,并且喜欢编写命令而不是使用图形用户界面(GUI).与Windows操作系统不同,在Windows中,大多数工作只需单击几下即可 ...

  5. linux c 结构体初始化的四种方法

    定义: struct InitMember {int first:double second:char* third:float four; }; 方法一:定义时赋值 struct InitMembe ...

  6. Linux测试端口的连通性的四种方法

    目录 1.telnet 2.ssh 3.crul 4.wget 方法一.telnet telnet为用户提供了在本地计算机上完成远程主机工作的能力,因此可以通过telnet来测试端口的连通性,具体用法 ...

  7. Linux 测试端口的连通性的四种方法

    工具: 1.telnet 2.ssh 3.crul 4.wget telnet telnet为用户提供了在本地计算机上完成远程主机工作的能力,因此可以通过telnet来测试端口的连通性,具体用法格式: ...

  8. c语言中字符串去掉逗号,JS四种方法去除字符串最后的逗号

    window.οnlοad=function() { var obj = {name: "xxx", age: 30, sex: "female"};//定义一 ...

  9. eclipse中linux打包,Eclipse中Maven打包程序并在Linux中运行

    Eclipse中Maven打包程序并在Linux中运行 1 在Eclipse中新建Maven工程 新建后的maven工程如下: 新建Maven工程的默认pom.xml如下,不需要修改: 4.0.0 T ...

最新文章

  1. 高考大数据:哪个省才是高考地狱模式?结论和想象不太一样
  2. 日10亿级处理,基于云的微服务架构
  3. SQL Server 索引和表体系结构(聚集索引)
  4. 优化内存中DataTable搜索速度,IP区域汇总
  5. Unity Game Starter Kit for Windows Store and Windows Phone Store games
  6. FreeRTOS — 临界段和开关中断
  7. numpy.floor详解
  8. 菜鸟要做架构师(一)——如何快速开发中小型系统
  9. c++中用于字符输入的函数
  10. b超可以看出什么_【b超能检查出什么】b超能看出男女吗_b超能查出什么妇科病 - 妈妈网百科...
  11. SAP UI5的source code map(源代码映射)机制
  12. tomcat应用服务器有哪些,手写一个Tomcat应用服务器
  13. DB2 9 底子(730 考试)认证指南,第 3 局部: 拜访 DB2 数据(3)
  14. 硬件基础 —— 光耦
  15. 搭建cocos2d-x-android环境 Windows XP3 + Eclipse + NDKR7+COCOS2DX(没有用到cygwin和minigw)
  16. Top 10 Digital Transformation Trends For 2020
  17. python中eval函数怎么用_python3中eval函数用法简介
  18. java 什么是封闭类,封闭类与声明类
  19. 【Unity 题型】Unity基础
  20. 推荐系统的常用算法原理和实现

热门文章

  1. JavaScript中函数文档注释
  2. Effective java 系列之更优雅的关闭资源-try-with-resources
  3. MySQL在登陆时出现ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)错误...
  4. PChar 类型的又一些用法
  5. push to origin/master was rejected错误解决方案(IDEA)
  6. 全球项目多区域数据同步问题解决方案
  7. 《Java并发编程入门与高并发面试》or 《Java并发编程与高并发解决方案》笔记
  8. 关于无法修改CheckBox样式的解决方案
  9. 用信号量和读写锁解决读者写者问题
  10. 错误:Parameter ‘0‘ not found.Available parameters are [arg1, arg0, param1, param2]的解决方法