Jemalloc (Jason Evans, 2006) 專為多線程並發設計,解決 glibc malloc 在多核下的鎖爭用瓶頸。核心優勢:
基準測試顯示:多線程分配吞吐較 glibc malloc 提升 2-3 倍,延遲抖動顯著降低。
# 源碼編譯安裝 (推薦指定版本)
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
./configure --prefix=/usr/local/jemalloc
make && make install
# 生效動態庫路徑
echo "/usr/local/jemalloc/lib" > /etc/ld.so.conf.d/jemalloc.conf
ldconfig
cmake ... \
-DCMAKE_EXE_LINKER_FLAGS="-ljemalloc" \
-DWITH_SAFEMALLOC=OFF \
... 其他參數
make && make install
原理:MySQL 啟動時直接鏈接 jemalloc 符號,所有內存分配 (InnoDB Buffer Pool、Sort Buffer、Join Buffer 等) 走 jemalloc 路徑,零開銷。
# 修改 mysqld_safe 啟動腳本
vim /usr/local/mysql/bin/mysqld_safe
# 在 "executing mysqld_safe" 行前插入:
export LD_PRELOAD=/usr/local/jemalloc/lib/libjemalloc.so
# 或使用 sed 自動修改
sed -i 's@executing mysqld_safe@export LD_PRELOAD=/usr/local/jemalloc/lib/libjemalloc.so\nexecuting mysqld_safe@' /usr/local/mysql/bin/mysqld_safe
# 重啟驗證
systemctl restart mysqld
# 檢查進程是否加載
lsof -p $(pidof mysqld) | grep jemalloc
# 輸出應包含 libjemalloc.so
innodb_buffer_pool_instances:設置為 CPU 核心數 (≤ 64),配合 jemalloc Arena 仿射。innodb_use_sys_malloc (MySQL 5.6+ 已棄用,默認用內部分配器)。jemalloc.stats.arenas.0.pactive 等指標觀察活躍頁數。
cd nginx-1.24.0
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-ld-opt="-L/usr/local/jemalloc/lib -ljemalloc" \
--with-cc-opt="-I/usr/local/jemalloc/include"
make && make install
驗證:
# 檢查二進制依賴
ldd /usr/local/nginx/sbin/nginx | grep jemalloc
# 輸出: libjemalloc.so.2 => /usr/local/jemalloc/lib/libjemalloc.so.2
# 運行時檢查 worker 進程
lsof -p $(pgrep -f "nginx: worker") | grep jemalloc
# 環境變量方式 (啟動前 export)
export MALLOC_CONF="background_thread:true,metadata_thp:auto,dirty_decay_ms:10000,muzzy_decay_ms:10000"
# 關鍵選項解釋
background_thread:true # 後台線程异步清理 dirty page,降低延遲抖動
metadata_thp:auto # 元數據使用透明大頁 (需內核支持)
dirty_decay_ms:10000 # Dirty page 10s 後釋放回 OS (默認 10s)
muzzy_decay_ms:10000 # Muzzy page 同理
narenas: # 顯式指定 Arena 數量,避免過多
percpu_arena:percpu # 每核綁定 Arena (Linux 4.4+)
top/pidstat 觀察 CPU 系統時間 (sy%) 下降、上下文切換減少。
# 導出統計
mallctl --help
# 程序化讀取 (C/C++/Go/Rust 綁定) 導出 stats.arenas..pactive, stats.allocated, stats.resident 等
# 定期抓取寫入 Prometheus,Grafana 看板
| 問題 | 原因 | 解決 |
|---|---|---|
| MySQL 啟動報錯 "jemalloc not found" | LD_PRELOAD 路徑錯或庫未安裝 | ldconfig 後 ldd 確認;絕對路徑 |
| Nginx 編譯報 "undefined reference to je_malloc" | --with-ld-opt 順序或路徑錯 | -L 在 -l 前;確認 libjemalloc.so 存在 |
| 內存佔用反而上升 | jemalloc 保留緩存 (retained memory) | 屬正常行為,resident 才是實際物理佔用;調大 decay_ms |
| 容器環境無效 | LD_PRELOAD 在容器外設置 | Dockerfile ENV MALLOC_CONF... 或 entrypoint.sh export |
| 與 tcmalloc 衝突 | 同時預載入兩個分配器 | 二選一,Jemalloc 穩定性更優 |
Jemalloc 通過 Arena 隔離、後台清理、大頁支持 徹底解決高併發內存分配瓶頸。MySQL 推薦 編譯期鏈接,Nginx 編譯期鏈接,二進制包場景用 LD_PRELOAD。配合 MALLOC_CONF 微調衰減時間、後台線程、Arena 數量,可榨乾硬件內存帶寬。生產上線前必須進行壓測對比 (sysbench, wrk),觀察 QPS、延遲 P99、CPU sy%、內存碎片率指標。