1. 课程导论:Buddy与Slab分配器在Linux内核中的地位与作用
Linux内核作为全球最广泛使用的开源操作系统内核,其内存管理子系统是系统性能与稳定性的基石。在内核的整个生命周期中,内存分配请求无处不在:从进程创建时分配页表,到网络协议栈分配sk_buff缓冲区,再到文件系统分配inode结构体。为了高效、可靠地管理这些请求,Linux内核构建了两套核心的内存分配器——Buddy分配器与Slab分配器。
理解这两套分配器的设计哲学、适用场景以及它们之间的协作关系,是深入掌握Linux内核内存管理的关键。本章将首先阐明它们各自在内核中的地位与作用,并解释为什么需要对比学习它们。
1.1 Buddy分配器:物理内存的“大管家”
Buddy分配器是Linux内核最底层的物理内存管理机制,直接管理系统的物理内存页(通常为4KB)。它的核心职责是解决外部碎片问题,并提供高效的大块连续物理内存分配。
- 核心算法:将空闲内存按2的幂次方(order)划分为块,相同大小的块互为“伙伴”(Buddy)。分配时,从满足需求的最小块开始,若没有则向上合并;释放时,检查伙伴是否空闲,若是则合并为更大的块。
- 主要作用:
- 管理所有物理内存页的分配与释放。
- 为DMA、设备驱动等需要连续物理内存的场景提供支持。
- 作为上层分配器(如Slab、vmalloc)的底层内存来源。
- 局限性:分配粒度最小为4KB(一个页面),对于大量小对象(如几十字节的struct file)会造成严重的内部碎片。
alloc_pages(gfp_mask, order)接口进行分配。
1.2 Slab分配器:小对象的“专属管家”
Slab分配器建立在Buddy分配器之上,专门用于管理内核中频繁创建和销毁的小对象(通常小于一个页面)。它的核心目标是解决内部碎片问题,并提高对象分配与释放的速度。
- 核心思想:将内存划分为多个“缓存”(cache),每个缓存专门管理一种特定大小的对象(如
struct task_struct、struct inode)。缓存内部由多个“slab”组成,每个slab包含多个连续的对象。 - 主要作用:
- 消除小对象分配导致的内部碎片。
- 通过对象复用和缓存着色(cache coloring)提高CPU缓存命中率。
- 提供对象构造函数/析构函数,支持对象初始化状态的复用。
- 演进版本:从早期的Slab分配器,到更高效的SLQB(已被移除),再到当前主流的SLUB分配器。SLUB简化了数据结构,减少了锁竞争,更适合多核系统。
slabtop 命令查看当前Slab缓存的占用情况。你会发现,像 dentry(目录项缓存)和 inode_cache 这样的缓存往往占用大量内存,这体现了Slab分配器在文件系统性能中的关键作用。
1.3 为什么需要对比学习它们?
单独学习Buddy或Slab分配器,容易陷入“只见树木,不见森林”的困境。对比学习能够帮助我们建立系统性的认知,理解它们如何协同工作以构成完整的内存管理解决方案。
| 对比维度 | Buddy分配器 | Slab分配器 |
|---|---|---|
| 管理粒度 | 物理页框(通常4KB及以上) | 任意大小的小对象(字节级) |
| 主要目标 | 解决外部碎片,提供连续大块内存 | 解决内部碎片,提高小对象分配效率 |
| 分配单位 | 2的幂次方个页面(order) | 预定义大小的对象(如32B、256B) |
| 底层依赖 | 直接操作硬件页表与内存节点 | 依赖Buddy分配器获取底层页面 |
| 典型用户 | 设备驱动、DMA、页缓存、vmalloc | 文件系统、网络协议栈、进程管理 |
| 碎片类型 | 外部碎片(已通过伙伴算法缓解) | 内部碎片(已通过对象复用消除) |
通过对比,我们可以清晰地看到:Buddy分配器解决了“有没有”和“够不够大”的问题,而Slab分配器解决了“用得好不好”和“浪不浪费”的问题。 两者缺一不可,共同构成了Linux内核内存分配器的完整图景。
1.4 整体架构关系
下面的SVG图展示了Buddy分配器与Slab分配器在Linux内核内存管理中的层级关系与协作流程。
1.5 对比学习的核心价值
在后续的课程中,我们将通过实践深入剖析两者的实现细节。对比学习将带来以下收益:
- 性能调优视角:当系统出现内存瓶颈时,能够快速定位是Buddy分配器的外部碎片问题,还是Slab分配器的缓存配置问题。
- 源码理解深度:通过对比,可以更清晰地理解
mm/page_alloc.c(Buddy核心)与mm/slub.c(SLUB核心)中不同数据结构和算法的设计动机。 - 问题排查能力:例如,通过
/proc/buddyinfo分析外部碎片程度,通过/proc/slabinfo分析小对象内存泄漏。
通过本章的导论,我们明确了Buddy与Slab分配器各自的核心定位与协作关系。接下来的课程,我们将深入它们的源码实现,并通过实际编程实验,亲手验证它们在不同负载下的表现差异。