1. 内存管理基础:伙伴系统与 Slab 分配器的关系,为什么需要 Slab 分配器

在操作系统内核中,物理内存管理是一个分层协作的系统。最底层负责将物理页框(Page Frame)以 4KB 为单位进行管理,而上层则需要为内核对象(如 task_struct、inode、socket 等)提供高效、低碎片的内存分配与回收。本章首先剖析底层伙伴系统(Buddy System)的运作机制,然后揭示其固有缺陷,从而引出 Slab 分配器存在的根本原因。

1.1 伙伴系统:物理页框的“批发商”

伙伴系统是内核管理物理页框的核心算法,其设计目标是以最小的外部碎片代价,快速分配和合并连续的物理页框。

  • 基本单位:物理页框(通常为 4KB)。
  • 核心思想:将空闲内存按 2 的幂次方(order)划分为不同大小的块(block)。每个块由连续的物理页框组成。
  • 分配策略:当请求 order=N 的块时,系统从 order=N 的空闲链表中查找。若找到则直接分配;若没有,则从 order=N+1 的链表中取出一块,将其分裂成两个 order=N 的“伙伴”块,一个分配出去,另一个挂入 order=N 的空闲链表。
  • 回收策略:释放块时,检查其“伙伴”块是否也为空闲。若是,则将两者合并为一个 order=N+1 的块,并继续向上合并,直到无法合并为止。
关键指标:伙伴系统将外部碎片控制在 2^order 个页框以内,但内部碎片可能高达 50%(例如申请 5KB 需要分配 8KB 的块)。
伙伴系统分裂与合并流程 伙伴系统分裂与合并流程 order=2 (16KB) order=1 (8KB) order=1 (8KB) order=0 (4KB) order=0 (4KB) 合并 说明 分裂:大块 → 小块(分配时) 合并:小块 → 大块(释放时) 伙伴:大小相同、地址相邻的块

1.2 伙伴系统的固有缺陷

尽管伙伴系统在管理连续物理页框方面表现出色,但它并不适合内核中频繁创建和销毁的小型对象。其缺陷主要体现在以下三个方面:

缺陷 具体表现 后果
内部碎片严重 内核对象通常只有几十到几百字节,而伙伴系统最小分配单位是 4KB。一个 200 字节的 task_struct 会浪费 3800+ 字节。 内存利用率极低,TLB 缓存效率下降。
频繁分配/释放开销大 每次分配都需要在空闲链表搜索、分裂;释放时需要合并检查。对于每秒创建/销毁数万个对象的场景(如网络连接),此开销不可接受。 系统吞吐量下降,CPU 时间浪费在内存管理上。
缺乏对象缓存与复用 伙伴系统每次分配返回的物理页框内容未初始化,释放后也不保留任何对象上下文。下次分配同一类型对象时,必须重新初始化。 对象构造/析构开销重复发生,cache 亲和性差。
性能陷阱:直接使用伙伴系统为内核对象分配内存,会导致严重的内部碎片和 CPU 开销。例如,在早期的 Linux 内核中,为每个进程描述符分配一个完整页框的做法已被证明是性能瓶颈。

1.3 为什么需要 Slab 分配器:从“批发”到“零售”

Slab 分配器的出现,正是为了解决伙伴系统在“小对象、高频次”场景下的无力感。它位于伙伴系统之上,扮演着“零售商”的角色,其核心设计哲学是 对象缓存(Object Caching)。

  • 消除内部碎片:Slab 分配器将伙伴系统分配的大块内存(一个或多个连续页框)切割成与对象大小完全匹配的“槽位”(slot),实现零内部碎片。
  • 减少分配开销:通过维护每个 CPU 的本地缓存(per-CPU cache),Slab 分配器可以在无锁或极少锁的情况下完成对象的分配和释放,极大降低了路径开销。
  • 对象复用与着色:释放的对象不会立即归还给伙伴系统,而是保留在 Slab 缓存中。下次分配同一类型对象时,直接从缓存中取出已初始化(或部分初始化)的对象,避免了重复的构造开销。此外,通过“着色”(coloring)技术优化对象在 CPU 缓存中的对齐,减少 cache line 冲突。
核心类比:伙伴系统是“建材批发市场”,按整箱(页框)出售;Slab 分配器是“五金零售店”,按颗螺丝钉(对象)零售,并且把常用螺丝钉放在收银台旁边的货架上(per-CPU cache)。
伙伴系统与 Slab 分配器层次关系 伙伴系统与 Slab 分配器层次关系 伙伴系统 (Buddy System) 管理物理页框,最小分配单位 4KB Slab 分配器 (Slab Allocator) 从伙伴系统获取页框,切割为对象槽位 维护 per-CPU 缓存,实现无锁快速分配 内核对象 (task_struct, inode, ...) 通过 Slab 分配器申请和释放内存 分配路径 对象 → Slab → 伙伴 释放路径相反

1.4 核心概念对比:伙伴系统 vs. Slab 分配器

下表从多个维度对比两种分配器,帮助理解它们各自的定位与协作关系。

对比维度 伙伴系统 Slab 分配器
管理粒度 物理页框(4KB 及以上,2 的幂次方) 任意大小的内核对象(字节级)
主要目标 减少外部碎片,管理连续物理内存 消除内部碎片,提高对象分配/释放速度
分配单位 2^order 个连续页框 预定义的对象大小(如 32B、64B、128B 等)
内部碎片 高(平均 50%) 极低(接近 0)
分配/释放速度 较慢(涉及分裂、合并、锁竞争) 极快(per-CPU 缓存,常为无锁操作)
对象复用 不支持 支持(缓存已释放对象,避免重复初始化)
适用场景 大块内存分配(> 1 页框)、DMA 缓冲区 内核高频小对象(进程描述符、文件节点等)

1.5 本章小结

伙伴系统提供了坚实的物理页框管理基础,但其粗粒度和高碎片特性无法满足内核高频小对象的分配需求。Slab 分配器作为伙伴系统的上层缓存层,通过对象切割、per-CPU 缓存和着色技术,完美弥补了伙伴系统的不足。两者形成“伙伴系统管大块、Slab 分配器管小块”的分层协作架构,共同构成了现代操作系统内核内存管理的基石。