为什么单线程下大家都差不多,mimalloc 是如何把跨线程释放开销压榨到极致的?

📅 2026/6/22 11:04:48
为什么单线程下大家都差不多,mimalloc 是如何把跨线程释放开销压榨到极致的?
把 larson 这个 benchmark 跑起来,你会看到一个不太好解释的数字。larson 模拟的是真实服务器里的内存行为:100 个线程,每个都疯狂地malloc和free,但关键在于——它们会把一部分对象留给别的线程去释放。Larson 和 Krishnan 1998 年管这叫 “bleeding”,渗血。这是几乎所有线上服务的常态:请求线程分配,工作线程或回收线程释放,对象在线程之间漂移。在 16 核 AMD EPYC 7000 上跑这个负载,mimalloc 比 tcmalloc 和 jemalloc 快 2.5 倍以上,比第二名 snmalloc 还快 48%(mimalloc 技术报告 §4.3)。这两个分配器是 Chrome 和 Firefox 用了十几年、被无数 profiler 抽打过的工业级代码,不存在"没调优"这种解释。奇怪的地方在这里:单看一次分配、一次释放,mimalloc 的快路径和它们差不多,都是从某条 free list 上摘一个块、还一个块,指令数是一个量级的。一次malloc在 mimalloc 里编译出来大约 7 条指令、一个分支(报告 §3.1)。tcmalloc 的 per-thread cache 命中路径也快得很。既然单次操作成本相当,2.5 倍的差距就不可能来自"分配算法更聪明"。那它来自哪?来自谁来还内存,以及还的时候走哪条路。把这个判断再逼紧一点。如果两个分配器的单次分配都是几条指令、单次本地释放也都是几条指令,那么在一个单线程的分配密集 benchmark 上,它们就该跑得差不多——事实也确实如此,报告里 cfrac、espresso 这类负载上各家差距