jemalloc替换标准库 malloc等函数的三种方式

1、LD_PRELOAD

使用LD_PRELOAD可以做到无侵入式替换,只需要在运行程序前设置envexport LD_PRELOAD=/path/to/jemalloc
注:编译jemalloc时不设置--with-jemalloc-prefix

cpp 复制代码
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <iostream>

// 当使用 export LD_PRELOAD= 预加载jemalloc库时
// malloc 将会被 jemalloc的符号替换, 做到无需修改源代码即可使用jemalloc

/**
 * @brief 原理
 * 
 * 加载顺序
 * 1、可执行程序
 * 2、LD_PRELOAD 库
 * 3、其他库,根据其在链接时的顺序
 * 
 * 当多个库中有相同符号时, 动态链接器会选择第一个加载的符号. 故使用 LD_PRELOAD 可以替换标准库的 malloc
 */

int main(int argc, char **argv)
{
    size_t size = 1024;
    void* ptr = malloc(size);
    if (!ptr) {
        std::cerr << "Memory allocation failed" << std::endl;
        return 1;
    }

    memset(ptr, 0, size);

    free(ptr);
    return 0;
}
2、代码中调用je_malloc

这种做法是侵入式的,如果没有jemalloc库将无法启动程序,另外编译代码时需要设置 --with-jemalloc-prefix=je_

cpp 复制代码
#include <cstdlib>
#include <stdio.h>
#include <string.h>
#include <iostream>

#include <jemalloc/jemalloc.h>

// 主动链接jemalloc时需要在编译时带上 --with-jemalloc-prefix=je_
// 不带时编译出来的符号就是 malloc, 防止冲突, 带上后符号是 je_malloc

int main()
{
    size_t size = 1024;
    void* ptr = je_malloc(size);
    if (!ptr) {
        std::cerr << "Memory allocation failed" << std::endl;
        return 1;
    }

    memset(ptr, 0, size);

    ::atexit([](){
        uint64_t epoch = 1;
        size_t sz = sizeof(epoch);
        je_mallctl("epoch", &epoch, &sz, &epoch, sz);

        size_t allocated, active, mapped;
        sz = sizeof(size_t);
        je_mallctl("stats.allocated", &allocated, &sz, NULL, 0);
        je_mallctl("stats.active", &active, &sz, NULL, 0);
        je_mallctl("stats.mapped", &mapped, &sz, NULL, 0);

        printf("allocated/active/mapped: %zu/%zu/%zu\n", allocated, active, mapped);
    });

    // 释放内存
    je_free(ptr);
    return 0;
}
3、使用hook方式

侵入式的,并且存在一定的不安全性

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <string>

#include <signal.h>

#include <unistd.h>
#include <dlfcn.h>

#include <jemalloc/jemalloc.h>

// 这种情况需要将 malloc/calloc 等全都 hook, 假设没有 hook realloc, 第三方库使用此函数申请的内存使用free会出现段错误
// c++ 重载 operator new/operator delete 一般是成对的, 默认的 new/delete 底层使用 malloc 无需考虑

struct ReplaceMallocFree
{
    using SelfMalloc = void *(*)(size_t);
    using SelfFree = void (*)(void *);

    ReplaceMallocFree()
    {
        m_malloc = (SelfMalloc)dlsym(RTLD_NEXT, "malloc");
        m_free = (SelfFree)dlsym(RTLD_NEXT, "free");

        assert(m_malloc && m_free);

        printf("malloc = %p, free = %p\n", m_malloc, m_free);
    }

    SelfMalloc  m_malloc;
    SelfFree    m_free;
};

ReplaceMallocFree g_replaceMallocFree;

#ifdef __cplusplus
extern "C" {
#endif

void* malloc(size_t size)
{
    // printf 有调用malloc行为, 会导致无限递归出现段错误
    write(STDOUT_FILENO, "---> malloc\n", 12);
    return je_malloc(size);
}

void free(void *ptr)
{
    write(STDOUT_FILENO, "---> free\n", 12);
    je_free(ptr);
}

#ifdef __cplusplus
}
#endif


void catch_sig(int32_t sig)
{
    if (sig == SIGABRT) {
        printf("\nSUCCESS\n");
    }

    exit(0);
}

int main()
{
    // 标准库的 free 检测到异常会调用 abort
    signal(SIGABRT, catch_sig);

    size_t size = 1024;
    void* ptr = malloc(size);
    if (!ptr) {
        printf("Memory allocation failed\n");
        return 1;
    }

    memset(ptr, 0, size);

    uint32_t *pp = new uint32_t;
    free(pp);

    printf("-------------\n");

    g_replaceMallocFree.m_free(ptr);
    return 0;
}
相关推荐
3DVisionary1 小时前
精密模具电极如何测形变?蓝光三维扫描3D检测方案解析
c++·数码相机·蓝光三维扫描·质量控制 qc·形位公差分析·模具电极检测·非接触三维测量
小小编程路1 小时前
C++类作用域
java·jvm·c++
计算机安禾2 小时前
【c++面向对象编程】第46篇:CRTP(奇异递归模板模式):静态多态的妙用
开发语言·c++·算法
hhcgchpspk2 小时前
easyx按键游戏
c++·stm32·单片机·游戏·easyx
郝学胜-神的一滴2 小时前
Qt 高级开发 011: 跨线程信号槽实战
开发语言·c++·qt·程序人生·开源软件·用户界面
学困昇2 小时前
Linux 动静态库制作与原理:从 .a、.so 到 ELF 加载一次讲透
linux·运维·服务器·c语言·开发语言·c++·人工智能
basketball6162 小时前
C++面试考点 头文件与实现文件形式
开发语言·c++
历程里程碑2 小时前
56 . 高效ET非阻塞IO服务器设计指南
java·运维·服务器·开发语言·数据结构·c++·排序算法
计算机安禾3 小时前
【c++面向对象编程】第44篇:typename与class的区别,依赖类型名与template消除歧义
java·jvm·c++
Hua-Jay3 小时前
OpenCV联合C++/Qt 学习笔记(二十五)----监督学习聚类及K均值聚类
c++·笔记·opencv·学习·计算机视觉·聚类