从零写OS内核-第十五篇:Slab分配器 —— 高效管理内核小对象
从零写 OS 内核-第十五篇:Slab 分配器 —— 高效管理内核小对象
“Buddy 系统擅长分配大块内存,但内核频繁申请 32 字节、128 字节的小对象怎么办? 今天,我们实现 Slab 分配器,让内核内存分配快如闪电!”
在上一篇中,我们构建了完整的内存管理体系:
Buddy 系统
管理物理页(4KB 粒度)
用户态 malloc
通过
brk
/
mmap
申请内存
但内核自身也有大量 小对象 需要频繁分配/释放: ✅ 进程控制块(PCB) ✅ 文件描述符(file) ✅ VFS 目录项(dentry) ✅ 网络缓冲区(skb)
如果每次用 kmalloc 都向 Buddy 申请 4KB 再切一小块, 内部碎片会高达 99% !
今天,我们就来实现 Slab 分配器 ——专为内核小对象设计的高效内存池, 让你的内核分配 PCB 时 零碎片、零初始化开销 !
🧱 一、为什么需要 Slab?Buddy 的痛点
Buddy 系统的局限:
| 场景 | 问题 |
|---|---|
| 分配 32 字节 | Buddy 返回 4KB 页,浪费 99.2% |
| 频繁分配/释放 | 每次都要清零内存(安全要求) |
| 缓存局部性差 | 对象分散在不同页,CPU 缓存命中率低 |
Slab 的核心思想:
“预分配一批同类型对象,用时即取,废时即还”
Slab
:一个或多个连续物理页,划分为固定大小的对象
Cache
:管理同类型对象的 Slab 池(如
task_cache
、
file_cache
)
对象复用
:释放的对象不归还 Buddy,而是放入空闲链表,下次直接复用
💡 Slab = 对象缓存 + 空闲链表 + 构造/析构回调
📦 二、Slab 核心数据结构
- kmem_cache(缓存描述符)
-
slab(内存页描述符)
🔑 关键技巧 :空闲对象的指针 直接存放在对象内存的开头 (节省额外内存)!
⚙️ 三、Slab 操作流程
- 创建缓存(kmem_cache_create)
-
分配对象(kmem_cache_alloc)
-
释放对象(kmem_cache_free)
🏗️ 四、初始化内核关键缓存
在内核启动早期,创建常用对象的缓存:
构造函数示例(初始化 PCB):
✅ 从此,创建新进程只需 kmem_cache_alloc(task_cache) ,无需手动初始化!
🔄 五、与 Buddy 系统的协作
Slab 分配器 底层仍依赖 Buddy 系统 获取物理页:
🌟 Slab 是 Buddy 的上层优化,两者协同工作!*
🧪 六、测试:内核对象分配性能
传统方式(无 Slab):
Slab 方式:
性能对比(假设分配 1000 个 PCB):
| 指标 | 传统方式 | Slab 方式 |
|---|---|---|
| 分配次数 | 1000 次 Buddy 调用 | ~4 次 Buddy 调用(每个 slab 256 个对象) |
| 初始化开销 | 1000 次 memset | 256 次(只在 slab 创建时) |
| 内存碎片 | 高(对象分散) | 低(对象紧凑) |
| CPU 缓存命中 | 低 | 高(局部性好) |
✅ Slab 在频繁分配小对象时,性能提升 10 倍以上!
⚠️ 七、Slab 的进阶优化
- 着色(Slab Coloring)
调整对象起始偏移,避免不同缓存的对象映射到同一 CPU 缓存行
提升多核性能 -
硬件缓存对齐
确保对象大小是 L1 缓存行(64 字节)的倍数
-
NUMA 感知
在多 CPU 插槽系统中,优先分配本地内存
-
对象冻结
当 slab 完全空闲时,延迟释放物理页(避免频繁 Buddy 调用)
💡 Linux 的 SLAB/SLUB/SLOB 分配器正是基于这些思想演进而来!
💬 写在最后
Slab 分配器看似复杂, 但它解决了内核内存管理的 根本矛盾 : 频繁分配小对象 vs 内存效率与性能 。
今天你实现的 kmem_cache_alloc , 正是 Linux 中 kmalloc 背后的核心机制之一。
🌟 高效的内存管理,是高性能操作系统的隐形翅膀。
📬 动手挑战 : 为你的 ext2 inode 实现 Slab 缓存,并测量创建 100 个文件的性能提升。 欢迎在评论区分享你的性能对比数据!
👇 下一篇你想看: 写时复制(CoW)实现 ,还是 内存压缩(zswap) ?
#操作系统 #内核开发 #内存管理 #Slab分配器 #kmalloc #内核对象 #从零开始
📢 彩蛋 :关注后回复关键词 “slab” ,获取:
完整 Slab 分配器代码(含 cache/slab 结构)
kmem_cache_create/alloc/free 实现
内核关键对象(task/file/inode)缓存初始化模板
评论