🎯 The Good, the Bad, and the Leaky: jemalloc, bumpalo, and mimalloc
📝 摘要
Meilisearch 开发团队详细记录内存泄漏调试过程,涉及三种不同的内存分配器:bumpalo、jemalloc 和 mimalloc。这是一个真实的生产环境内存问题排查案例。
🔑 核心亮点
1. bumpalo::Vec::into_bump_slice 陷阱
根本原因:在 bumpalo::Vec 中存储了 std::Vec(使用全局分配器的数据结构)
bumpalo::Vec::into_bump_slice将分配的向量转换为底层 slice- 这个 slice 不会运行 drop glue
- 当在 bumpalo::Vec 中存储 std::Vec 时,内存永远不会释放
- 这个 bug 从 v1.12 存在了约 1.5 年
2. LMDB 与自定义分配器不兼容
- 问题:Meilisearch 使用 LMDB(内存映射 key-value 存储)+ mimalloc(全局分配器)
- 冲突:LMDB 使用系统默认分配器,不使用 mimalloc
- 结果:LMDB 分配和释放的页面无法被 Meilisearch 重用,因为两个分配器不协作
3. 统一分配器解决方案
使用单一内存分配器对整个应用栈进行审计至关重要
- 移除自定义全局分配器,使用 jemalloc + LD_PRELOAD
- 启用 jemalloc 分析功能生成内存报告
- 解决了 LMDB 和应用之间的分配器隔离问题
- 使用 jemalloc 后,内存泄漏消失
4. AI 辅助调试
- 使用 jemalloc 生成堆分析报告
- 将报告提供给 Zed 中的 Claude Sonnet 4.5 Agent
- AI 找到了约 4 个泄漏,其中 1 个是真实的
- 经验:AI 辅助可以加速调试,但需要人工验证
5. 分配器选择历程
| 分配器 | 原因 |
|---|---|
| jemalloc | 最初选择,性能好,有用的泄漏追踪工具 |
| mimalloc | Windows/macOS 兼容性考虑(微软项目) |
| jemalloc(回归) | 解决 LMDB 跨分配器内存审计问题 |
💡 核心洞察
"使用单一内存分配器对整个应用栈进行审计至关重要"
当应用使用多个内存分配器时,不同分配器分配的内存无法相互复用,可能导致看似"泄漏"但实际是分配器隔离的问题。
🔗 原文链接
The Good, the Bad, and the Leaky: jemalloc, bumpalo, and mimalloc in meilisearch
📅 发现日期
2026-03-21