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 profiling | no |
--enable-stats | 启用统计信息 | yes |
--enable-debug | 启用调试模式(大幅降低性能) | no |
--enable-fill | 默认填充已分配内存(检测未初始化访问) | no |
--enable-xmalloc | malloc 失败时 abort | no |
--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 概述 下一章:第 3 章:架构与原理