从零写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 核心数据结构

  1. kmem_cache(缓存描述符)

  2. slab(内存页描述符)

🔑 关键技巧 :空闲对象的指针 直接存放在对象内存的开头 (节省额外内存)!


⚙️ 三、Slab 操作流程

  1. 创建缓存(kmem_cache_create)

  2. 分配对象(kmem_cache_alloc)

  3. 释放对象(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 的进阶优化

  1. 着色(Slab Coloring)

    调整对象起始偏移,避免不同缓存的对象映射到同一 CPU 缓存行
    提升多核性能

  2. 硬件缓存对齐

    确保对象大小是 L1 缓存行(64 字节)的倍数

  3. NUMA 感知

    在多 CPU 插槽系统中,优先分配本地内存

  4. 对象冻结

    当 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)缓存初始化模板

最后修改: 2026年7月1日

作者

评论

发表评论

您的邮箱地址不会被公开。