3. 伙伴系统数据结构
伙伴系统的核心数据结构围绕三个层次展开:区域(zone)、迁移类型(migrate type) 和 阶(order)。理解 free_area 数组、struct page、zone 结构体以及 buddy bitmap 的协作关系,是掌握伙伴系统内存分配与回收机制的基础。
3.1 zone 结构体:内存区域的“总控室”
每个 struct zone 描述一个物理内存区域(如 ZONE_DMA、ZONE_NORMAL、ZONE_HIGHMEM)。伙伴系统在该区域内的所有操作,都通过 zone 结构体中的 free_area 数组和 pageblock_flags 等字段进行管理。
| 字段 | 类型 | 说明 |
|---|---|---|
free_area[MAX_ORDER] |
struct free_area |
按阶(order)组织的空闲页块链表数组,每个元素对应一个阶 |
pageblock_flags |
unsigned long * |
页块迁移类型位图,用于防治内存碎片 |
managed_pages |
unsigned long |
伙伴系统管理的物理页总数 |
watermark[NR_WMARK] |
unsigned long |
内存水位线(min/low/high),控制回收触发时机 |
关键点:zone 结构体中的
free_area 数组是伙伴系统分配器的直接操作对象,而 pageblock_flags 位图则用于实现迁移类型分组,两者共同决定了内存分配的行为和碎片防治效果。
3.2 free_area 数组:按阶组织的空闲页块链表
free_area[MAX_ORDER] 是伙伴系统的核心索引结构。数组下标 order 表示页块的阶(0 到 MAX_ORDER-1,通常 MAX_ORDER=11),每个元素包含一个链表头和一个位图。
// include/linux/mmzone.h
struct free_area {
struct list_head free_list[MIGRATE_TYPES];
unsigned long *map; // buddy bitmap
};
- free_list[MIGRATE_TYPES]:每个迁移类型对应一个链表,链入该阶下该迁移类型的空闲页块。
- map:指向
buddy bitmap的指针,用于快速判断两个页块是否为伙伴。
设计意图:将空闲页块按阶和迁移类型双重分类,使得分配时能快速定位到满足大小和碎片防治要求的页块,避免遍历整个空闲链表。
3.3 struct page:物理页的“身份证”
每个物理页框对应一个 struct page 实例,伙伴系统通过该结构体管理页面的状态、引用计数和链表指针。
| 字段 | 说明 |
|---|---|
flags |
页面标志位,如 PG_buddy(标记该页属于伙伴系统)、PG_private 等 |
_refcount |
引用计数,用于页面共享和释放判断 |
lru |
链表节点,用于将页面链入 free_area 的 free_list 或 LRU 链表 |
private |
当页面作为伙伴系统页块时,存储该页块的 order 值 |
zone |
指向所属 zone 的指针,用于快速定位区域信息 |
注意:当页面被伙伴系统管理时,
PG_buddy 标志位被置位,此时 lru 字段用于链入 free_list,private 字段存储该页块所属的阶。一旦页面被分配出去,这些字段的语义会发生变化。
3.4 buddy bitmap:伙伴关系判定位图
每个 free_area 元素包含一个位图 map,用于快速判断两个连续页块是否为伙伴。位图的每一位对应一对候选伙伴页块。
- 位图大小:对于阶
order,位图位数 =zone 总页数 >> (order + 1)。 - 位图含义:某位为 1 表示该对伙伴中至少有一个页块是空闲的;为 0 表示两个页块都已分配或都不存在。
- 作用:在释放页块时,通过位图快速判断伙伴是否空闲,从而决定是否合并。
// 判断两个页块是否为伙伴的简化逻辑
static inline unsigned long find_buddy(unsigned long page_idx, unsigned int order) {
return page_idx ^ (1 << order);
}
// 通过 buddy bitmap 检查伙伴是否空闲
static inline int buddy_is_free(struct page *buddy, unsigned int order) {
unsigned long buddy_idx = page_to_pfn(buddy);
unsigned long bit = buddy_idx >> (order + 1);
return test_bit(bit, zone->free_area[order].map);
}
3.5 数据结构关系总览
下图展示了 zone、free_area、struct page 和 buddy bitmap 之间的协作关系:
3.6 数据结构协作流程
- 分配请求到达:内存分配器根据请求大小计算所需阶
order,并确定迁移类型migratetype。 - 定位 free_area:从 zone 的
free_area[order]开始查找,若该阶有空闲页块,则从对应迁移类型的free_list[migratetype]中取出。 - 无空闲则升级:若当前阶无空闲,则向高阶查找,找到后分裂页块,并将低阶页块插入对应
free_list。 - 更新位图:分配或释放页块时,同步更新
buddy bitmap对应位,确保伙伴关系判定准确。 - 释放与合并:释放页块时,通过
buddy bitmap检查伙伴是否空闲,若空闲则合并为高阶页块,并递归向上合并。
性能关键点:buddy bitmap 的位操作和 free_list 的链表操作都是 O(1) 或 O(log N) 级别,保证了伙伴系统分配和释放的高效性。迁移类型分组则通过将不同生命周期的页面隔离,有效减少了长期不可移动页面导致的碎片问题。