SLUB 小对象分配机制与实现详解
源码路径:
rk3588/kernel-6.1/mm/slub.c、slab_common.c
内核版本:Linux 6.1(RK3588,通常CONFIG_SLUB=y)
文档目录:linuxDoc/mm/
目录
一、原理
1.1 为什么需要 slab
内核大量 固定大小小对象(task_struct、inode、sk_buff 头等),若每对象一次 __alloc_pages(0):
- 浪费内存(页内碎片)
- 增加 buddy 锁竞争
Slab 分配器 以 页为 slab,在页内切分等长 object,按 cache 复用。
1.2 SLUB 设计思想
SLUB(Six Less Unfair Buddy)相对 SLAB/SLOB:
- per-CPU slab 指针:热路径无中心锁
- 合并 partial slab 管理:减少 per-node 链表遍历
- freelist 在 object 内嵌指针:减少元数据
RK3588 defconfig 一般启用 CONFIG_SLUB,禁用 SLAB/SLOB。
1.3 三级存储层次
1.4 kmalloc
kmalloc(size, gfp) 根据 size 索引到预建 kmalloc-* cache(slab_common.c 中 create_kmalloc_caches),本质仍是 kmem_cache_alloc。
二、实现方式
2.1 核心对象
| 结构 | 说明 |
|---|---|
struct kmem_cache |
对象大小、对齐、构造函数、flags |
struct slab |
一页或多页容器,freelist、inuse、frozen |
struct kmem_cache_cpu |
per-CPU:slab、freelist、tid |
struct kmem_cache_node |
per-node partial/full 链表 + list_lock |
2.2 分配入口
1 | void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) |
→ slab_alloc() → slab_alloc_node() → ___slab_alloc()。
2.3 快路径(inlined)
slub.c 中 slab_alloc_node 内联路径:
- 取
cpu_slab = slub_get_cpu_ptr(s->cpu_slab) - 若
c->slab存在且c->freelist非空:直接从 freelist 弹对象(get_freepointer) - 使用
tid检测 CPU 迁移,不一致则走慢路径
2.4 慢路径:___slab_alloc
get_partial():从 node partial 链表取 slab- 若无:
new_slab()→allocate_slab()→alloc_pages(order 由oo/min_partial决定) - 新 slab 标记
frozen,填入 CPU slab - debug 模式走
alloc_single_from_new_slab与 red zone
2.5 释放:kmem_cache_free
- 快路径:对象放回 CPU freelist
__slab_free:慢路径,可能将 slab 合并到 partial、或discard_slab归还 buddydeactivate_slab:flush 当前 CPU slab 到 node 链表
2.6 slab_common.c 引导
| 函数 | 时机 |
|---|---|
create_boot_cache |
极早期创建 task_struct 等 cache |
kmem_cache_init |
建立基本 cache |
kmem_cache_init_late |
完整 kmalloc cache 表 |
create_kmalloc_caches |
按 size 分档 |
2.7 调试与硬化
| CONFIG | 目录/行为 |
|---|---|
| SLUB_DEBUG | redzone、poison |
| KASAN | kasan/ 插桩 |
| KFENCE | kfence/ 采样检测 |
| FAILSLAB | failslab.c 故障注入 |
三、关键数据结构与接口
| API | 说明 |
|---|---|
kmem_cache_create |
创建 cache |
kmem_cache_alloc |
分配对象 |
kmem_cache_free |
释放对象 |
kmem_cache_alloc_node |
指定 NUMA node |
kmem_cache_alloc_bulk |
批量分配 |
kmalloc / kfree |
通用大小分配 |
锁顺序(slub.c 文件头):slab_mutex → node->list_lock → cpu_slab->lock。
四、与页分配器关系
- SLUB 不替代 buddy;slab 页来自
alloc_pages(gfp, order)。 - 若 buddy 失败,SLUB 返回 NULL,调用方处理;可能间接触发 OOM(见 08 文档)。
__GFP_COMP:folio/slub 大对象可能使用复合页。
五、调试与观测
| 手段 | 说明 |
|---|---|
/proc/slabinfo |
各 cache 对象数、大小 |
/sys/kernel/slab/ |
sysfs 详情 |
slab_nomerge 启动参数 |
禁止合并 cache |
附录:源码索引
| 主题 | 文件 | 约略行号 |
|---|---|---|
| kmem_cache_alloc | slub.c | 3420 |
| ___slab_alloc | slub.c | 3100–3260 |
| __slab_free | slub.c | 3459 |
| kmem_cache_init | slub.c | 4818 |
| kmalloc caches | slab_common.c | 869 |
正在加载留言…