强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

02 - 安装与编译

第 2 章:安装与编译

2.1 安装方式总览

方式适用场景优点缺点
包管理器快速体验、开发环境简单快速版本可能较旧
源码编译生产环境、自定义配置版本可控、可裁剪需要构建工具
LD_PRELOAD无需修改已有程序零侵入全局影响
静态链接分发二进制无运行时依赖增大二进制体积

2.2 包管理器安装

Ubuntu / Debian

# 更新包索引
sudo apt update

# 安装 libjemalloc 开发库(含运行时库 + 头文件)
sudo apt install libjemalloc-dev

# 验证安装
dpkg -L libjemalloc-dev
# 查看库文件
ls /usr/lib/x86_64-linux-gnu/libjemalloc*
包名内容
libjemalloc2运行时共享库 libjemalloc.so.2
libjemalloc-dev开发头文件 + 静态库 + pkg-config

CentOS / RHEL / Fedora

# CentOS 8 / RHEL 8
sudo dnf install jemalloc-devel

# CentOS 7
sudo yum install jemalloc-devel

# Fedora
sudo dnf install jemalloc-devel

# 验证
rpm -ql jemalloc-devel

macOS

# 使用 Homebrew
brew install jemalloc

# 查看安装路径
brew --prefix jemalloc
# 通常为 /usr/local/opt/jemalloc 或 /opt/homebrew/opt/jemalloc

# 验证
ls $(brew --prefix jemalloc)/lib/

Arch Linux

sudo pacman -S jemalloc

注意:包管理器提供的版本通常不是最新版。如需最新特性或安全修复,建议从源码编译。


2.3 源码编译

2.3.1 获取源码

# 从 GitHub 克隆
git clone https://github.com/jemalloc/jemalloc.git
cd jemalloc

# 查看可用版本
git tag | sort -V | tail -5
# 5.2.1  5.2.1-3-g7ff36261  5.3.0  5.3.0-14-g14b82bab

# 切换到稳定版本
git checkout 5.3.0

或者直接下载发布包:

wget https://github.com/jemalloc/jemalloc/releases/download/5.3.0/jemalloc-5.3.0.tar.bz2
tar xjf jemalloc-5.3.0.tar.bz2
cd jemalloc-5.3.0

2.3.2 标准编译流程

# 1. 配置(自动检测平台)
./configure --prefix=/usr/local

# 2. 编译(-j 指定并行度)
make -j$(nproc)

# 3. 可选:运行测试
make check

# 4. 安装
sudo make install

# 5. 刷新动态链接器缓存
sudo ldconfig

# 6. 验证
ls /usr/local/lib/libjemalloc*
# libjemalloc.a  libjemalloc.so  libjemalloc.so.2

2.3.3 常用编译选项

选项说明默认值
--prefix=<path>安装路径/usr/local
--enable-prof启用 heap profilingno
--enable-stats启用统计信息yes
--enable-debug启用调试模式(大幅降低性能)no
--enable-fill默认填充已分配内存(检测未初始化访问)no
--enable-xmallocmalloc 失败时 abortno
--with-jemalloc-prefix=<prefix>添加函数名前缀
--with-malloc-conf=<conf>编译时嵌入默认配置
--disable-cxx禁用 C++ new/delete 重载no
--enable-lazy-lock延迟加载 pthread(针对单线程优化)no

生产环境推荐编译选项

./configure \
  --prefix=/usr/local \
  --enable-prof \
  --enable-stats \
  --enable-fill \
  --with-malloc_conf="background_thread:true,dirty_decay_ms:5000"

make -j$(nproc)
sudo make install
sudo ldconfig

2.3.4 自定义前缀编译

当项目中需要同时使用 jemalloc 和其他分配器时,可以给 jemalloc 的函数添加前缀:

# 添加前缀 "my_",最终函数名为 my_malloc, my_free 等
./configure --prefix=/usr/local --with-jemalloc-prefix=my_

make -j$(nproc)
sudo make install

在代码中使用:

#include <jemalloc/jemalloc.h>

int main() {
    // 使用带前缀的函数
    void *p = my_malloc(128);
    my_free(p);

    // 或使用宏(定义在 jemalloc.h 中)
    void *q = malloc(128);  // 实际调用 my_malloc
    free(q);                // 实际调用 my_free
    return 0;
}

2.3.5 交叉编译

以 ARM64 为例:

# 安装交叉编译工具链
sudo apt install gcc-aarch64-linux-gnu

# 配置交叉编译
./configure \
  --prefix=/opt/jemalloc-aarch64 \
  --host=aarch64-linux-gnu \
  --enable-prof

make -j$(nproc)
make install DESTDIR=./output

2.4 macOS 编译注意事项

# macOS 默认使用 Apple Clang,部分选项不同
./configure \
  --prefix=/usr/local \
  --enable-prof

# macOS 需要额外注意:
# 1. 没有 ldconfig,使用 install_name_tool
# 2. 系统 SIP 保护 /usr/lib,不要安装到那里
# 3. Apple Silicon (M1/M2) 需要确认架构

# 验证架构
file /usr/local/lib/libjemalloc.dylib
# 应显示 arm64 或 x86_64

2.5 Windows 编译

jemalloc 在 Windows 上的支持有限,推荐方式:

# 使用 vcpkg
vcpkg install jemalloc

# 或使用 MSYS2/MinGW
pacman -S mingw-w64-x86_64-jemalloc

注意:Windows 上 jemalloc 的功能和性能不如 Linux/macOS 完善。Windows 用户可优先考虑 mimalloc。


2.6 LD_PRELOAD 使用

LD_PRELOAD 是在不修改已有程序的情况下使用 jemalloc 的最简单方法。

基本用法

# 对单个程序使用 jemalloc
LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 ./my_program

# 设置环境变量(当前 shell 会话生效)
export LD_PRELOAD=/usr/local/lib/libjemalloc.so.2
./my_program

# 写入 ~/.bashrc 永久生效
echo 'export LD_PRELOAD=/usr/local/lib/libjemalloc.so.2' >> ~/.bashrc

配合 MALLOC_CONF 使用

# 同时配置 jemalloc 参数
LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 \
MALLOC_CONF="narenas:8,dirty_decay_ms:3000" \
./my_server

systemd 服务中使用

# /etc/systemd/system/my-service.service
[Service]
Environment="LD_PRELOAD=/usr/local/lib/libjemalloc.so.2"
Environment="MALLOC_CONF=narenas:4,background_thread:true"
ExecStart=/usr/local/bin/my-server

检查是否生效

# 方法 1:检查进程加载的共享库
LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 cat /proc/self/maps | grep jemalloc

# 方法 2:使用 ldd
LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 ldd /bin/ls

# 方法 3:检查 mallinfo
cat << 'EOF' > check_jemalloc.c
#include <stdio.h>
#include <malloc.h>

int main() {
    struct mallinfo mi = mallinfo();
    printf("arena: %d KB\n", mi.arena / 1024);
    printf("uordblks: %d KB (in-use)\n", mi.uordblks / 1024);
    return 0;
}
EOF
gcc -o check_jemalloc check_jemalloc.c

# 对比输出差异
./check_jemalloc
LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 ./check_jemalloc

2.7 与系统 malloc 共存

方法一:编译时链接

# 显式链接 jemalloc
gcc -o my_app main.c -ljemalloc -lpthread

# 如果 jemalloc 安装在非标准路径
gcc -o my_app main.c -I/usr/local/include -L/usr/local/lib -ljemalloc -lpthread

# 设置运行时库路径
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

方法二:自定义前缀

# 编译带自定义前缀的 jemalloc
./configure --prefix=/opt/jemalloc --with-jemalloc-prefix=je_
make -j$(nproc) && sudo make install
// 在代码中显式使用 je_ 前缀
#include <jemalloc/jemalloc.h>

void *p = je_malloc(1024);  // 明确使用 jemalloc
je_free(p);

// 系统 malloc 仍然可用
void *q = malloc(1024);     // 使用 glibc malloc
free(q);

方法三:使用 wrapper

// my_alloc.h
#ifndef MY_ALLOC_H
#define MY_ALLOC_H

#ifdef USE_JEMALLOC
#include <jemalloc/jemalloc.h>
#define MY_MALLOC(sz)       je_malloc(sz)
#define MY_FREE(p)          je_free(p)
#define MY_REALLOC(p, sz)   je_realloc(p, sz)
#define MY_CALLOC(n, sz)    je_calloc(n, sz)
#else
#include <stdlib.h>
#define MY_MALLOC(sz)       malloc(sz)
#define MY_FREE(p)          free(p)
#define MY_REALLOC(p, sz)   realloc(p, sz)
#define MY_CALLOC(n, sz)    calloc(n, sz)
#endif

#endif

2.8 验证安装的完整示例

创建一个综合测试程序:

// test_jemalloc.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifdef USE_JEMALLOC
#include <jemalloc/jemalloc.h>
#endif

int main() {
    printf("=== jemalloc Installation Test ===\n\n");

    // 1. 基本分配/释放
    void *p = malloc(1024);
    if (!p) { perror("malloc"); return 1; }
    memset(p, 0xAA, 1024);
    printf("[OK] malloc(1024) -> %p\n", p);
    free(p);

    // 2. 大块分配
    void *big = malloc(4 * 1024 * 1024);  // 4MB
    if (big) {
        printf("[OK] malloc(4MB) -> %p\n", big);
        free(big);
    }

    // 3. calloc
    int *arr = (int *)calloc(100, sizeof(int));
    if (arr) {
        printf("[OK] calloc(100, %zu) -> %p\n", sizeof(int), arr);
        free(arr);
    }

    // 4. realloc
    char *buf = (char *)malloc(64);
    buf = (char *)realloc(buf, 2048);
    if (buf) {
        printf("[OK] realloc(64 -> 2048) -> %p\n", buf);
        free(buf);
    }

    // 5. 如果使用 jemalloc,打印统计信息
#ifdef USE_JEMALLOC
    printf("\n=== jemalloc Stats ===\n");
    je_malloc_stats_print(NULL, NULL, NULL);
#endif

    // 6. mallinfo
    struct mallinfo mi = mallinfo();
    printf("\n=== mallinfo ===\n");
    printf("  arena:     %d KB\n", mi.arena / 1024);
    printf("  uordblks:  %d KB (in-use)\n", mi.uordblks / 1024);
    printf("  fordblks:  %d KB (free)\n", mi.fordblks / 1024);

    printf("\n[ALL TESTS PASSED]\n");
    return 0;
}
# 编译测试(链接 jemalloc)
gcc -O2 -DUSE_JEMALLOC -o test_jemalloc test_jemalloc.c -ljemalloc
./test_jemalloc

# 或使用 LD_PRELOAD
gcc -O2 -o test_jemalloc_sys test_jemalloc.c
LD_PRELOAD=/usr/local/lib/libjemalloc.so.2 ./test_jemalloc_sys

2.9 常见安装问题

问题 1:找不到 libjemalloc.so

# 检查是否已安装
find / -name "libjemalloc*" 2>/dev/null

# 添加库路径
echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/jemalloc.conf
sudo ldconfig

问题 2:编译时报 autoconf 相关错误

# 安装构建依赖
sudo apt install autoconf automake libtool  # Debian/Ubuntu
sudo dnf install autoconf automake libtool  # Fedora/CentOS

# 如果从 git 克隆,需要先运行
./autogen.sh

问题 3:LD_PRELOAD 无效

# 检查库的架构是否匹配
file /usr/local/lib/libjemalloc.so.2
file /usr/bin/your_program

# 检查依赖
ldd /usr/local/lib/libjemalloc.so.2

# 在容器中使用时,确保库文件在容器内可访问

问题 4:与 AddressSanitizer 冲突

# ASan 会替换 malloc/free,与 jemalloc 冲突
# 调试时不要同时使用:
gcc -fsanitize=address -o test test.c -ljemalloc  # ❌ 冲突!

# 正确做法:调试时移除 jemalloc
gcc -fsanitize=address -o test test.c  # ✅

2.10 本章小结

任务推荐方式
快速体验apt install libjemalloc-dev
生产部署源码编译 --enable-prof --enable-stats
无侵入接入LD_PRELOAD
精确控制自定义前缀 --with-jemalloc-prefix

扩展阅读

  1. jemalloc 安装文档
  2. LD_PRELOAD 工作原理
  3. GCC 与链接器选项详解

上一章第 1 章:jemalloc 概述 下一章第 3 章:架构与原理