1. Linux伙伴系统:物理内存管理的基石
在Linux内核的世界里,内存管理就像一座精密的钟表,而伙伴系统(Buddy System)就是其中最核心的齿轮。作为一名长期与内核打交道的开发者,我见证了太多因为不理解伙伴系统而导致的内存问题。今天,就让我们深入这个看似简单却极其精妙的内存管理机制。
伙伴系统要解决的核心问题是外部碎片。想象一下你的书桌:频繁地取放不同大小的书本后,桌面上会散布各种大小的空隙,虽然总空间足够,但却放不下一本大书。物理内存也是如此,频繁的分配释放会产生大量不连续的小块内存,无法满足大块连续内存需求。伙伴系统通过"合并相邻空闲页帧"的机制,从根本上解决了这个问题。
关键认知:伙伴系统管理的是连续的物理页帧,这是它与slab分配器的本质区别。slab负责小对象分配,而伙伴系统则是物理内存的"批发商"。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 伙伴系统的核心设计
2.1 基本概念与数据结构
伙伴系统的最小管理单位是物理页帧(struct page),分配粒度则是2的幂次方个页帧。这种设计不是偶然的,而是经过精心考量的:
- 2的幂次方使得地址对齐非常简单,只需通过位操作就能完成
- 拆分和合并操作可以递归进行,算法实现优雅高效
- 保证了分配的内存绝对连续,满足DMA等特殊需求
核心数据结构free_area是一个数组+链表的组合体:
c复制struct free_area {
struct list_head free_list[MIGRATE_TYPES];
unsigned long nr_free;
};
这个结构体体现了Linux内核设计的精妙之处:
- 数组下标对应页帧块的大小阶数(order)
- 每个链表节点是一个连续的页帧块
- MIGRATE_TYPES实现了内存规整优化
2.2 伙伴关系的严格定义
两个连续的物理页帧要成为伙伴,必须满足三个严苛条件:
- 大小相同(均为2^k个页帧)
- 物理地址连续且无缝衔接
- 起始页帧的页号是2^(k+1)的整数倍
这种设计确保了:
- 合并后的内存块仍然满足对齐要求
- 可以快速通过位运算找到伙伴块
- 内存块的拆分和合并操作对称且高效
在实际操作中,我经常通过下面这个函数来验证两个页块是否为伙伴:
c复制s
