首页 > 系统相关 >在应用程序中替换Linux中Glibc的malloc的四种方法_转

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

时间:2022-10-17 00:12:38浏览次数:96  
标签:__ malloc void 内存 Linux wrap Glibc size

转自:在应用程序中替换Linux中Glibc的malloc的四种方法--csdn

打算优化系统的内存分配,接管glibc提供的内存管理,但是整个工程的代码量很大,使用malloc、realloc、calloc和free的地方到处都是,如果自己写好的接口需要重命名所有的调用,先不说工作量,部分没有权限查看代码的.a文件就搞不定了。所以需要替换掉系统的malloc,保证原有调用的名称不变。经过尝试,共有四种方法可以替换,各有优缺点吧。

方案1 使用环境变量LD_PRELOAD

环境变量LD_PRELOAD指定程序运行时优先加载的动态连接库,这个动态链接库中的符号优先级是最高的。标准C的各种函数都是存放在libc.so.6的文件中,在程序运行时自动链接。使用LD_PRELOAD后,自己编写的malloc的加载顺序高于glibc中的malloc,这样就实现了替换。用法:

$LD_PRELOAD=" ./mymalloc.so"

这是最实用的替换方法,动态链接库加载过程中提供了初始化函数,可以轻易的获得系统malloc的句柄,再将它做进一步的管理,Hoard(参见深入Linux的内存管理,关于PTMalloc3、Hoard和TCMalloc)的就是这样实现的。

方案2 malloc调试变量

__malloc_hook是一组glibc提供的malloc调试变量中的一个,这组变量包括:

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 myprogmyprog.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分配的内存复杂了很多。

2015-12-22更新:

这个方法对于运行时动态链接的库中调用的malloc/new都可以接管,但是对于程序启动后使用dlopen且开启RTLD_DEEPBIND选项加载的动态链接库,其中的malloc和new是不能替换的。

方案4 链接过程控制

ld中有一个选项 –wrap,当查找某个符号时,它优先先解析__wrap_symbol, 解析不到才去解析symbol。例如:

void *__wrap_malloc (size_t c)
{
     printf ("malloc called with %zu/n", c);
     return __real_malloc (c);
}

当其它文件与你实现__wrap_malloc函数的文件链接时使用--wrapmalloc ,则所有到malloc的调用都是会链接到__wrap_malloc上。只有调用__reall_malloc时才会调用真正的malloc。

#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;
}

编译

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

运行

$./wrap

My MALLOCcalled: 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"。

实测方案4可行

需要替换malloc相关系列函数:

#include <malloc.h>

#ifdef DEFINE_MALLOC
_PTR 
_malloc_r (struct _reent *r, size_t sz)
{
  return malloc (sz);
}
#endif

#ifdef DEFINE_CALLOC
_PTR 
_calloc_r (struct _reent *r, size_t a, size_t b)
{
  return calloc (a, b);
}
#endif

#ifdef DEFINE_FREE
void
_free_r (struct _reent *r, _PTR x)
{
  free (x);
}
#endif

#ifdef DEFINE_REALLOC
_PTR 
_realloc_r (struct _reent *r, _PTR x, size_t sz)
{
  return realloc (x, sz);
}
#endif

 

参考:

1. GCC的-Wl,--wrap编译选项

2. mallocr.c -- github.com

标签:__,malloc,void,内存,Linux,wrap,Glibc,size
From: https://www.cnblogs.com/embedded-linux/p/16797677.html

相关文章

  • Linux 常用命令学习
    1、ls命令就是list的缩写,通过ls命令不仅可以查看linux文件夹包含的文件,而且可以查看文件权限(包括目录、文件夹、文件权限)查看目录信息等等。常用参数搭配:ls-a......
  • 20201302姬正坤Linux第四章学习笔记
    第四章并发编程一、并行计算导论1、顺序算法与并行算法在描述顺序算法中,常用一个begin-end代码块列出算法。该代码块中的所有步骤都是通过某个任务依次执行的。而并行......
  • Linux结构化命令
    结构化命令定义可用于执行流程控制和改变执行顺序与语句ifcommand语句(命令退出状态码)if...thenif根据command命令返回码来判断是否执行,如果返回码的值为0,就执......
  • linux命令随笔
    用于记录平时遇到的比较有用的命令。Vim命令查找​ vim进入编辑模式之后,如果想在文件中查找某个关键字的话可以用/关键字,随后回车,文件中的关键字会高亮显示,摁n可以调......
  • LiveGBS流媒体服务平台国标GB28181级联上级如何抓包分析windows抓包和Linux抓包
    LiveGBS流媒体服务平台国标GB28181级联上级如何抓包分析windows抓包和Linux抓包​​1、第一步:抓包工具准备​​​​1.1、Linux​​​​1.2、windows​​​​2、第二步:找到级......
  • Linux学习笔记 | Bash基本命令
    (一)历史命令<history>格式:history[选项][历史命令保存文件]选项: -c:   清空历史命令 -w:  把缓存中的历史命令写入历史命令保存文件(~/.bash_history) 历史命令......
  • archlinux + i3wm 使用 tauri 开发者模式 (react + ts) 预览白屏 解决方法
    在我这台机器只需将tauri.conf.json的devPath的localhost改成127.0.0.1即可参考来源https://github.com/tauri-apps/tauri/issues/1140......
  • Linux专项练习
    grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。grep全称是GlobalRegularExpressionPrint,表示全局正则表达式版本,它的使用权限是......
  • Linux 下指定端口开放访问权限
    Linux下指定端口开放访问权限作者:Grey原文地址:博客园:Linux下指定端口开放访问权限CSDN:Linux下指定端口开放访问权限环境CentOS系和Debian系的防火墙开放的命令......
  • Windows不分区VHD装Linux多系统(七):ubuntu 22.04.1安装实验
    一、安装过程:环境:1.物理机系统:Win102. ISO镜像:ubuntu-22.04.1-desktop-amd64.iso3.虚拟机:VirtualBox图形用户界面,版本6.1.36r152435(Qt5.6.2)    安......