从当前 CPU 的空闲链表快速分配内核对象
Linux SLUB 将同类对象组织在 slab 中,并用 per-CPU freelist 满足常见分配,避免每次都访问集中管理的部分空闲 slab 列表。
工程问题#
内核频繁分配与释放固定规格的小对象;若每次都进入共享分配结构,多 CPU 会争用管理状态。
实际实现#
__slab_alloc_node 读取当前 CPU 的 freelist、slab 和事务标识 tid。快路径适用且对象、NUMA 节点等条件满足时,从链表取对象,并将 freelist 与下一 tid 一起进行本 CPU 比较交换;更新失败便重试,不满足条件则进入慢路径。
处理流程#
- 读取当前 CPU 的事务标识、空闲对象头和 slab
- 检查快路径开关、可用对象及目标 NUMA 节点
- 比较交换 freelist 与 tid,成功则返回对象,冲突则重试
- 缺少可用对象或快路径不适用时进入补充或分配 slab 的慢路径
源码片段#
固定版本 · 原文摘录3557static inline bool3558__update_cpu_freelist_fast(struct kmem_cache *s,3559 void *freelist_old, void *freelist_new,3560 unsigned long tid)3561{3562 freelist_aba_t old = { .freelist = freelist_old, .counter = tid };3563 freelist_aba_t new = { .freelist = freelist_new, .counter = next_tid(tid) };35643565 return this_cpu_try_cmpxchg_freelist(s->cpu_slab->freelist_tid.full,3566 &old.full, new.full);3567}把旧 freelist 与旧 tid 作为一个待比较状态,把新 freelist 与递增后的 tid 作为新状态;本 CPU 比较交换同时验证并更新二者。
3956 object = c->freelist;3957 slab = c->slab;39583959 if (!USE_LOCKLESS_FAST_PATH() ||3960 unlikely(!object || !slab || !node_match(slab, node))) {3961 object = __slab_alloc(s, gfpflags, node, addr, c, orig_size);3962 } else {3963 void *next_object = get_freepointer_safe(s, object);3964快路径未启用、freelist 为空、没有当前 slab 或节点不匹配时进入 __slab_alloc。只有通过检查才准备取出下一个空闲对象;后续原子更新失败会回到 redo 重试。
片段分别展示联合状态更新和快慢路径条件。完整重试逻辑位于 __slab_alloc_node,不能把 helper 当成独立可复用的通用无锁栈。
收益与取舍#
工程分析带来的收益
- 常见分配使用 per-CPU 状态,减少对集中 partial 列表锁的访问
- 事务标识与链表头联合验证,检测被抢占、迁移或期间发生的本 CPU 状态变化
付出的代价
- per-CPU 缓存与部分填充 slab 可能保留空闲内存,需权衡局部性与内存占用
- 重试、慢路径、NUMA 和调试钩子都会改变成本;不能宣称所有分配恒定时间或无锁
- 这段比较交换只保护对应本 CPU 操作,并非任意跨 CPU 链表访问协议
可比较的选择
集中空闲对象链表管理状态较集中,但多 CPU 操作需要更多共享同步。
伙伴页分配器解决按页、按阶的连续块分配;SLUB 位于其上层处理小对象,二者并非直接替换关系。
版本与适用范围#
Linux v6.12,非 CONFIG_SLUB_TINY 的对象分配路径。PREEMPT_RT 不使用该无锁快路径;源码中的慢路径、调试配置与平台原子原语需要一并阅读。
参考来源#
源码、官方文档与原始论文mm/slub.c · SLUB locking / USE_LOCKLESS_FAST_PATH
相关实现与比较#
4 个相关案例伙伴分配器把空闲物理页组织为不同 order 的连续块,并用空闲链表管理同阶块。
limit_req 把漏桶计算、红黑树查状态与队列回收组合起来,按配置的 key 管理请求速率。
QEMU 的 QEMUTimerList 用有序单链表维护定时器,链表头就是下一到期项。
缓存块命中后可能需要从队列中间移除,双向链表让这一步保持常数时间。