jemalloc 是一个通用内存分配器malloc 实现核心作用是替代 glibc 默认的 ptmalloc2在多线程高并发场景下显著降低内存碎片、提升分配效率。jemalloc有以下主要的优点多 arena 无锁设计每个线程绑定独立 arena大幅减少锁竞争内存碎片控制按大小分级small/large/huge class减少内部碎片和外部碎片缓存友好tcache线程局部缓存 伙伴系统热点小对象分配无需进入全局锁Redis 为什么要用 jemalloc面试重点Redis 在编译时默认链接 jemalloc--allocatorjemalloc核心原因有两条① 减少内存碎片——直接影响 Redis 内存利用率Redis 是纯内存数据库内存碎片率直接决定一台机器能存多少数据jemalloc 的分级分配策略对小对象如 Redis 的 robj、sds、dictEntry的分配对齐做得更好碎片率通常比 ptmalloc2 低 10%30%实测高负载下 jemalloc 碎片率 ≈ 1.011.05ptmalloc2 可达 1.2② 多线程/高并发场景的性能优势Redis 虽然是单线程事件循环但AOF rewrite、RDB save、主从同步、Lazy Free等后台操作会产生多线程分配/释放。jemalloc 的 tcache per-thread arena 使这些后台线程与主线程的内存操作互不干扰避免 ptmalloc2 的全局锁竞争导致的性能抖动。③ 内存压缩背景页回收友好jemalloc 支持dirty_decay_ms配置可控制脏页回收速度与 Redis 的maxmemory策略配合更平滑在redis中jemalloc主要提升了以下性能指标提升幅度经验值说明内存利用率提升 10%30%同等物理内存可存更多 Key碎片率从 1.2 降至 1.011.05INFO memory 命令可见高负载下的延迟稳定性P99 尾延迟降低 20%后台线程与主线程争抢减少大内存实例32GB的稳定性显著提升ptmalloc2 在大内存下碎片膨胀严重jemalloc 的使用场景场景典型项目原因内存数据库/缓存Redis、Memcached内存利用率是核心 KPI关系型数据库MySQLInnoDB、MariaDBBuffer Pool 频繁分配释放碎片影响大消息队列KafkaJVM 之外、RocketMQ 的 PageCache 层高吞吐 IO 线程的分配需求大数据/实时计算ClickHouse、Druid海量小对象分配需控制碎片高并发 Web 服务器Nginx部分定制版本、Netty 的 Native Memory多 worker 进程各自独立 arena原理讲解jemalloc 通过 per-thread arena size-class 分级分配解决了 Redis 在高碎片率和高并发后台线程场景下的内存浪费与锁竞争问题使同等硬件下能承载更多数据、延迟更稳定。per-thread arena每个线程自己的小仓库没有 jemalloc 的时候传统方式公司只有一个巨大的公共仓库全局内存池。所有快递员线程要拿包裹都得跑到这个仓库门口排队。一次只能一个人进去拿其他人都在外面等着加锁。人多的时候光排队就浪费了大量时间而且仓库里面乱糟糟的包裹扔得到处都是产生内存碎片。有了 jemalloc 的 per-thread arena 之后jemalloc 给每个快递员线程都分配了一个专属的小仓库arena。每个快递员只需要在自己的小仓库里拿放包裹不需要和别人抢同一个大门无锁或极少锁竞争。好处1速度快。不用排队了每个快递员各干各的并发能力大大提升。好处2隔离性好。张三把他的包裹弄得再乱也只影响他自己的小仓库不会搞乱李四和王五的仓库。回到 Redis 的例子Redis 的主线程负责处理你的查询请求有自己的小仓库后台做数据保存AOF重写/RDB快照的线程也有它们自己的小仓库。主线程在处理你的GET/SET时不会被后台线程的内存操作打断或拖慢。size-class 分级分配分类货架没有 jemalloc 的时候传统方式仓库里只有一种巨大的货架。不管你是要放一个钥匙扣1字节还是要放一台冰箱1MB都得占用一整格货架的空间。这就导致了严重的浪费明明只需要1字节的空间却被划走了1MB的格子剩下的空间全浪费了这叫内部碎片。有了 jemalloc 的 size-class 分级分配之后jemalloc 把仓库里的货架分成了很多不同尺寸的专用格子size classes就像超市里的货架分区一样小物件区Small Class专门放8字节、16字节、32字节……这种很小的东西。中等物件区Large Class专门放几KB到几MB的东西。大物件区Huge Class专门放超大块的东西。当你需要申请一块内存时jemalloc 会根据你要求的尺寸把你领到最合适的那个货架前给你一个刚好能装下、又不浪费太多空间的格子。回到 Redis 的例子Redis 里存的最多的东西就是各种小对象比如一个简单的字符串hello、一个哈希表的条目。这些东西都很小。如果用传统的分配器这些小东西会把巨大的内存格子塞得乱七八糟导致大量内存被浪费碎片率高。而 jemalloc 把它们都规规矩矩地放进对应的小物件区货架上整整齐齐空间利用率极高。总结成一个比喻per-thread arena 每个员工都有自己的专属工具箱不用大家抢一个公用工具箱干活更快。size-class 分级分配 工具箱里有各种尺寸的格子螺丝刀槽、扳手槽每种工具都能严丝合缝地放进去不会晃来晃去浪费空间。所以 jemalloc 在 Redis 里的作用就是让 Redis 这个超级仓库管理员在同时应对成千上万个客户请求多线程和处理大量小物件小对象时既能干得快减少锁竞争又能装得多减少内存碎片。安装使用所以 jemalloc 在 Redis 里的作用就是让 Redis 这个超级仓库管理员在同时应对成千上万个客户请求多线程和处理大量小物件小对象时既能干得快减少锁竞争又能装得多减少内存碎片。第一步安装开发包apt-get update apt-get install libjemalloc-dev第二步验证是否有安装成功dpkg -l | grep libjemalloc如果只看到libjemalloc1或libjemalloc2这样的运行时库而没有libjemalloc-dev那就是开发包没装。在/usr/lib/x86_64-linux-gnu/目录下会自动创建libjemalloc.so的软链接。第三步链接1、编译时添加链接参数在编译你的simple-redis或类似项目时在编译命令或 Makefile 的链接选项中加入-ljemallocg -stdc17 your_source.cpp -ljemalloc -o your_program如果是用 Makefile可以在LDFLAGS中添加LDFLAGS ... -ljemalloc2、运行时加载这种方式通过环境变量LD_PRELOAD在程序启动时“劫持”所有内存分配函数无需重新编译即可生效。第一步找到 jemalloc 动态库路径安装后库文件通常在这里# 常见路径 /usr/lib/x86_64-linux-gnu/libjemalloc.so第二步使用 LD_PRELOAD 启动程序# 运行你的 simple-redis LD_PRELOAD/usr/lib/x86_64-linux-gnu/libjemalloc.so ./your-redis-server # 运行 redis-benchmark 测试 LD_PRELOAD/usr/lib/x86_64-linux-gnu/libjemalloc.so redis-benchmark ...要取消这种加载只需要unset LD_PRELOAD或重新打开终端。高级调优通过环境变量配置 jemallocjemalloc 还提供了MALLOC_CONF环境变量允许你动态调整内存管理策略例如启用后台线程回收内存或调整线程缓存大小export MALLOC_CONFbackground_thread:true,dirty_decay_ms:10000 LD_PRELOAD/usr/lib/x86_64-linux-gnu/libjemalloc.so ./your-redis-server
jemelloc通用内存分配器
jemalloc 是一个通用内存分配器malloc 实现核心作用是替代 glibc 默认的 ptmalloc2在多线程高并发场景下显著降低内存碎片、提升分配效率。jemalloc有以下主要的优点多 arena 无锁设计每个线程绑定独立 arena大幅减少锁竞争内存碎片控制按大小分级small/large/huge class减少内部碎片和外部碎片缓存友好tcache线程局部缓存 伙伴系统热点小对象分配无需进入全局锁Redis 为什么要用 jemalloc面试重点Redis 在编译时默认链接 jemalloc--allocatorjemalloc核心原因有两条① 减少内存碎片——直接影响 Redis 内存利用率Redis 是纯内存数据库内存碎片率直接决定一台机器能存多少数据jemalloc 的分级分配策略对小对象如 Redis 的 robj、sds、dictEntry的分配对齐做得更好碎片率通常比 ptmalloc2 低 10%30%实测高负载下 jemalloc 碎片率 ≈ 1.011.05ptmalloc2 可达 1.2② 多线程/高并发场景的性能优势Redis 虽然是单线程事件循环但AOF rewrite、RDB save、主从同步、Lazy Free等后台操作会产生多线程分配/释放。jemalloc 的 tcache per-thread arena 使这些后台线程与主线程的内存操作互不干扰避免 ptmalloc2 的全局锁竞争导致的性能抖动。③ 内存压缩背景页回收友好jemalloc 支持dirty_decay_ms配置可控制脏页回收速度与 Redis 的maxmemory策略配合更平滑在redis中jemalloc主要提升了以下性能指标提升幅度经验值说明内存利用率提升 10%30%同等物理内存可存更多 Key碎片率从 1.2 降至 1.011.05INFO memory 命令可见高负载下的延迟稳定性P99 尾延迟降低 20%后台线程与主线程争抢减少大内存实例32GB的稳定性显著提升ptmalloc2 在大内存下碎片膨胀严重jemalloc 的使用场景场景典型项目原因内存数据库/缓存Redis、Memcached内存利用率是核心 KPI关系型数据库MySQLInnoDB、MariaDBBuffer Pool 频繁分配释放碎片影响大消息队列KafkaJVM 之外、RocketMQ 的 PageCache 层高吞吐 IO 线程的分配需求大数据/实时计算ClickHouse、Druid海量小对象分配需控制碎片高并发 Web 服务器Nginx部分定制版本、Netty 的 Native Memory多 worker 进程各自独立 arena原理讲解jemalloc 通过 per-thread arena size-class 分级分配解决了 Redis 在高碎片率和高并发后台线程场景下的内存浪费与锁竞争问题使同等硬件下能承载更多数据、延迟更稳定。per-thread arena每个线程自己的小仓库没有 jemalloc 的时候传统方式公司只有一个巨大的公共仓库全局内存池。所有快递员线程要拿包裹都得跑到这个仓库门口排队。一次只能一个人进去拿其他人都在外面等着加锁。人多的时候光排队就浪费了大量时间而且仓库里面乱糟糟的包裹扔得到处都是产生内存碎片。有了 jemalloc 的 per-thread arena 之后jemalloc 给每个快递员线程都分配了一个专属的小仓库arena。每个快递员只需要在自己的小仓库里拿放包裹不需要和别人抢同一个大门无锁或极少锁竞争。好处1速度快。不用排队了每个快递员各干各的并发能力大大提升。好处2隔离性好。张三把他的包裹弄得再乱也只影响他自己的小仓库不会搞乱李四和王五的仓库。回到 Redis 的例子Redis 的主线程负责处理你的查询请求有自己的小仓库后台做数据保存AOF重写/RDB快照的线程也有它们自己的小仓库。主线程在处理你的GET/SET时不会被后台线程的内存操作打断或拖慢。size-class 分级分配分类货架没有 jemalloc 的时候传统方式仓库里只有一种巨大的货架。不管你是要放一个钥匙扣1字节还是要放一台冰箱1MB都得占用一整格货架的空间。这就导致了严重的浪费明明只需要1字节的空间却被划走了1MB的格子剩下的空间全浪费了这叫内部碎片。有了 jemalloc 的 size-class 分级分配之后jemalloc 把仓库里的货架分成了很多不同尺寸的专用格子size classes就像超市里的货架分区一样小物件区Small Class专门放8字节、16字节、32字节……这种很小的东西。中等物件区Large Class专门放几KB到几MB的东西。大物件区Huge Class专门放超大块的东西。当你需要申请一块内存时jemalloc 会根据你要求的尺寸把你领到最合适的那个货架前给你一个刚好能装下、又不浪费太多空间的格子。回到 Redis 的例子Redis 里存的最多的东西就是各种小对象比如一个简单的字符串hello、一个哈希表的条目。这些东西都很小。如果用传统的分配器这些小东西会把巨大的内存格子塞得乱七八糟导致大量内存被浪费碎片率高。而 jemalloc 把它们都规规矩矩地放进对应的小物件区货架上整整齐齐空间利用率极高。总结成一个比喻per-thread arena 每个员工都有自己的专属工具箱不用大家抢一个公用工具箱干活更快。size-class 分级分配 工具箱里有各种尺寸的格子螺丝刀槽、扳手槽每种工具都能严丝合缝地放进去不会晃来晃去浪费空间。所以 jemalloc 在 Redis 里的作用就是让 Redis 这个超级仓库管理员在同时应对成千上万个客户请求多线程和处理大量小物件小对象时既能干得快减少锁竞争又能装得多减少内存碎片。安装使用所以 jemalloc 在 Redis 里的作用就是让 Redis 这个超级仓库管理员在同时应对成千上万个客户请求多线程和处理大量小物件小对象时既能干得快减少锁竞争又能装得多减少内存碎片。第一步安装开发包apt-get update apt-get install libjemalloc-dev第二步验证是否有安装成功dpkg -l | grep libjemalloc如果只看到libjemalloc1或libjemalloc2这样的运行时库而没有libjemalloc-dev那就是开发包没装。在/usr/lib/x86_64-linux-gnu/目录下会自动创建libjemalloc.so的软链接。第三步链接1、编译时添加链接参数在编译你的simple-redis或类似项目时在编译命令或 Makefile 的链接选项中加入-ljemallocg -stdc17 your_source.cpp -ljemalloc -o your_program如果是用 Makefile可以在LDFLAGS中添加LDFLAGS ... -ljemalloc2、运行时加载这种方式通过环境变量LD_PRELOAD在程序启动时“劫持”所有内存分配函数无需重新编译即可生效。第一步找到 jemalloc 动态库路径安装后库文件通常在这里# 常见路径 /usr/lib/x86_64-linux-gnu/libjemalloc.so第二步使用 LD_PRELOAD 启动程序# 运行你的 simple-redis LD_PRELOAD/usr/lib/x86_64-linux-gnu/libjemalloc.so ./your-redis-server # 运行 redis-benchmark 测试 LD_PRELOAD/usr/lib/x86_64-linux-gnu/libjemalloc.so redis-benchmark ...要取消这种加载只需要unset LD_PRELOAD或重新打开终端。高级调优通过环境变量配置 jemallocjemalloc 还提供了MALLOC_CONF环境变量允许你动态调整内存管理策略例如启用后台线程回收内存或调整线程缓存大小export MALLOC_CONFbackground_thread:true,dirty_decay_ms:10000 LD_PRELOAD/usr/lib/x86_64-linux-gnu/libjemalloc.so ./your-redis-server