内存分配器的一次"外科手术式"升级
Linux 7.2 合并窗口日前合入了一组针对 SLUB 分配器的性能优化补丁,涵盖三项核心改进:延迟空闲链表构建、批量 partial slab 分离/重接,以及颇具前瞻性的 Allocation Tokens(分配令牌) 机制。
这三项优化分别来自 ZTE 工程师盛明虎、内核开发者郝力,以及 LLVM/clang 编译器社区的前沿探索。本文逐一拆解其原理、收益与适用场景。
一、延迟空闲链表构建:不做无用功
问题在哪?
SLUB 分配器在分配一个新 slab(即一整页内存)时,传统做法是立即初始化整个 freelist——把 slab 内所有空闲对象的指针串成一个链表。这个过程需要遍历每个对象并写入指针,本身就是一笔不小的开销。
但一个关键观察是:当你批量分配对象时,新 slab 中的大部分(甚至全部)对象很快就会被分配出去。先构建 freelist 再逐个拆走,等于先把积木搭好再一块块拆掉——中间步骤完全是浪费。
优化思路
盛明虎提交的 commit dc795d4c 实现了"延迟构建":只在真正需要时才构造 freelist 指针。如果一次性分配走 slab 中的所有对象,那 freelist 根本无需完整构建。
收益多大?
基准测试 slub_bulk_bench 的数据很亮眼:
| |
|---|
| CONFIG_SLAB_FREELIST_RANDOM=n | 42% ~ 70% |
| 58% ~ 69% |
当然,这是最佳场景下的数字。实际负载的收益取决于"到达新 slab 的频率"——如果你的应用频繁触发新 slab 分配,收益就越明显。
具体应用场景?
对于运行 KVM 虚拟化、数据库或高频内存分配场景的宿主机来说,这意味着一部分 slab 分配路径的延迟被直接砍半。虽然单次分配节省的是纳秒级开销,但积少成多,在微服务网关、CDN 边缘节点这类对 tail latency 敏感的场景中,这种"无感优化"恰恰是最安全的性能提升——你什么都不用改,内核帮你省掉了无用功。
二、批量 partial slab 分离/重接:减少链表锁操作
问题在哪?
SLUB 维护着多个 partial slab 链表(部分空闲的 slab),分配和释放时频繁涉及将 slab 从链表中取出或放回。每次操作都要拿锁、遍历、调整指针——单个操作的开销不大,但架不住次数多。
郝力的提交 commit 0fc52dee 将这个过程的粒度从"逐个操作"改为"批量处理":一次性从链表中取下多个 slab,或者一次性将多个 slab 重接到链表中。
收益
- will-it-scale mmap 基准测试提升 2%~5%
- 减少 list 锁竞争和 cache line bouncing
工程思维
这个优化思路在内核中并不陌生——将多次小操作合并为一次大操作,摊销固定开销。KVM 的批量 MMU 更新、IO 层的 bio 合并、网络层的 TSO/GRO……都是同一哲学的不同体现。
批量,是操作系统工程师对抗延迟的通用武器。
三、Allocation Tokens:让编译器教分配器"认人"
这是三个优化中最具前瞻性的一个。
思路
当前 SLUB 的 kmalloc cache 是按**大小(size class)**划分的——8 字节、16 字节、32 字节……不同大小的对象进入不同的 slab。但问题是:同一大小 class 中混入了不同类型的对象,它们的分配/释放模式可能完全不同,互相干扰导致碎片化和缓存效率下降。
Allocation Tokens 的思路是:利用 LLVM Clang 22+ 的编译器插桩,在分配点嵌入类型标签(token),让分配器知道"这个分配来自什么类型的对象",从而更智能地划分 cache。
技术栈
- 需要 Clang 22+ 的支持(目前 LLVM 的最新开发版本)
- 分配器根据 token 将同类型的对象分配到同一 slab 中
意义
这代表一种趋势:编译器与内核的边界正在模糊化。传统上,内存分配器对"谁在分配"一无所知——它看到的只是一个 size 和一个 GFP flag。而 Allocation Tokens 让编译器的静态类型信息流到了运行时分配器层面,类似 THP(透明大页)让虚拟化层更智能的思路。
当然,这个特性还处于早期阶段,实际收益的 benchmark 数据尚未完全公开。但它打开了一扇门:当编译器可以"告诉"分配器更多上下文,分配策略就能从"通用最优"走向"场景最优"。
四、对 KVM/虚拟化场景的连锁影响
作为一个内存密集型子系统,KVM 虚拟化对 slab 分配器的变化较为敏感:
| |
|---|
| |
| |
| 长期看,虚拟机控制结构(如 VMCS、kvm_vcpu)可分配到更紧凑的 cache 中 |
VM 启动时,内核需要为 vCPU、VMCS 区域、内存映射等结构大量分配 slab 对象。这些路径正好是上述优化的覆盖范围。
五、写在最后
Linux 7.2 的这一波 SLUB 优化,三个补丁各有侧重:
- 延迟 freelist
- 批量操作
- Allocation Tokens
这三种优化哲学,放在任何一个系统里都适用。
最后值得一提的是,两个关键补丁分别来自 ZTE 的盛明虎和独立内核开发者郝力——中国开发者在 Linux 内存子系统的影响力正在持续增长。Allocation Tokens 虽然当前依赖 Clang 22+,暂时无法进入大多数生产环境,但它代表的方向值得每个内核关注者持续跟踪。
参考:Phoronix — “Linux 7.2 Slab Changes Include More Performance Optimizations” (2026-06-17)