Kernel Buddy 分配器:Page Block Size 实现原理与工作机制深度解析
1. 基础概念
1.1 Page Block Size 定义
在 Linux 内核的 Buddy(伙伴)分配器中,Page Block Size(页面块大小)是一个逻辑上的内存管理单位,它定义了**迁移类型(Migrate Type)**管理的最小粒度。
虽然 Buddy 分配器可以分配小至 4KB(Order 0)的页面,但在进行内存碎片整理(Compaction)和反碎片化(Anti-fragmentation)策略时,内核是以 PageBlock 为单位进行管理的。每个 PageBlock 中的所有页面通常被标记为相同的迁移类型(如 MIGRATE_MOVABLE, MIGRATE_UNMOVABLE, MIGRATE_RECLAIMABLE)。
1.2 物理内存管理中的作用
Page Block Size 的引入主要为了解决 外部碎片(External Fragmentation) 问题:
- 反碎片化机制:通过将具有相同生命周期特性的页面(如均可移动的用户态匿名页)归类到同一个 PageBlock 中,内核可以避免不可移动的页面(如内核分配的页面)散落在可移动页面中间,从而阻碍大页(Huge Page)的分配。
- 内存规整(Compaction):当需要分配大块连续物理内存(如 HugeTLB)时,内存规整扫描器会以 PageBlock 为单位检查是否可以通过移动页面来腾出连续空间。
1.3 不同架构下的典型配置
Page Block Size 的大小通常由 pageblock_order 决定,其值依赖于架构和配置(特别是 HugeTLB 的配置)。
| 架构/配置 | Page Size | MAX_ORDER | Page Block Order | Page Block Size |
|---|---|---|---|---|
| x86_64 (Default) | 4KB | 11 | 9 (通常对应 2MB HugePage) | 2MB |
| ARM64 (4KB Pages) | 4KB | 11 | 9 | 2MB |
| ARM64 (64KB Pages) | 64KB | 14 | 13 (对应 512MB HugePage) | 512MB |
| No HugeTLB | 4KB | 11 | MAX_ORDER - 1 (10) |
4MB |
注意 :
pageblock_order通常设定为 HugeTLB 页面的阶数(Order),这确保了内核能够有效地管理和分配大页。
2. 技术实现细节
2.1 核心数据结构
Page Block 的管理主要依赖于 struct zone 中的 pageblock_flags 位图。
struct zone (include/linux/mmzone.h)
c
struct zone {
/* ... */
#ifndef CONFIG_SPARSEMEM
/*
* Flags for a pageblock_nr_pages block. See pageblock-flags.h.
* In SPARSEMEM, this map is stored in struct mem_section
*/
unsigned long *pageblock_flags;
#endif /* CONFIG_SPARSEMEM */
/* ... */
};
pageblock_order 定义 (include/linux/pageblock-flags.h)
c
#ifdef CONFIG_HUGETLB_PAGE
#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
extern unsigned int pageblock_order;
#else
#define pageblock_order HUGETLB_PAGE_ORDER
#endif
#else
#define pageblock_order (MAX_ORDER-1)
#endif
#define pageblock_nr_pages (1UL << pageblock_order)
2.2 数据结构关系图
下图展示了 struct zone、page_map 与 PageBlock 之间的逻辑映射关系。

(图示说明:物理内存被划分为多个 PageBlock,每个 PageBlock 在 zone->pageblock_flags 位图中拥有对应的 bits 来存储其迁移类型)
2.3 核心代码路径
- 初始化 :
mm/page_alloc.c: free_area_init_core()->setup_usemap(): 为pageblock_flags分配内存。
- 获取/设置类型 :
include/linux/pageblock-flags.h: get_pageblock_migratetype(page)mm/page_alloc.c: set_pageblock_migratetype(page, migratetype)
- Fallback 机制 :
mm/page_alloc.c: __rmqueue_fallback(): 当指定类型的空闲页不足时,从其他类型的 PageBlock 借用内存,甚至改变整个 PageBlock 的类型。
关键函数调用关系 (Mermaid)
Order > 0 Order > 0 / Fallback __alloc_pages_nodemask get_page_from_freelist rmqueue __rmqueue_smallest __rmqueue_fallback Change PageBlock Type set_pageblock_migratetype Update zone->pageblock_flags
3. 工作机制分析
3.1 内存分割与合并
Buddy 分配器利用 Page Block Size 来隔离不同可移动性的页面。
- 分割 :当请求一个
MIGRATE_MOVABLE页面但该类型链表为空时,内核可能会从MIGRATE_UNMOVABLE的 PageBlock 中"偷取"页面。如果偷取的页面数量达到一定阈值(通常是一半以上),或者直接偷取了一个大块,整个 PageBlock 的属性可能会被修改为MIGRATE_MOVABLE。 - 合并:释放页面时,Buddy 系统会尝试合并相邻的空闲页。如果合并后的块跨越了 PageBlock 边界(虽然物理上连续,但逻辑上属于不同管理块),通常不会改变 PageBlock 的属性,除非发生特定的大范围规整。
3.2 运行时状态转换示例
假设系统内存紧张,需要分配一个 MOVABLE 的页面:
- 初始状态 :
- Block A (Order 9):
MIGRATE_UNMOVABLE(内核数据使用) - Block B (Order 9):
MIGRATE_MOVABLE(用户数据使用,已满)
- Block A (Order 9):
- 分配请求 :
- 请求
alloc_pages(GFP_HIGHUSER_MOVABLE, 0)
- 请求
- Fallback 处理 (
__rmqueue_fallback):- 扫描
MIGRATE_UNMOVABLE列表。 - 找到 Block A 中有空闲的大块内存。
- 关键决策 :如果从 Block A 分配,是否改变 Block A 的类型?
- 如果偷取的是大块(>= pageblock_order / 2),倾向于将整个 Block A 标记为
MIGRATE_MOVABLE。
- 如果偷取的是大块(>= pageblock_order / 2),倾向于将整个 Block A 标记为
- 扫描
- 结果 :
- Block A 变为
MIGRATE_MOVABLE。后续的内核不可移动分配将无法使用 Block A 中剩余的空间(除非再次发生 Fallback),从而保护了该 Block 能够逐渐形成大的连续可移动空间。
- Block A 变为
3.3 分配/释放处理流程
Yes No Yes Yes No No 开始 请求内存页 当前迁移类型
有空闲页? 从 buddy 链表摘除 进入 __rmqueue_fallback 扫描备用迁移类型列表 找到空闲块? 偷取页面块 偷取大小 >=
PageBlock一半? 修改 PageBlock
迁移类型属性 仅分配页面 结束 触发回收/OOM
4. 性能优化考量
4.1 Page Block Size 对碎片化的影响
Page Block Size 是内存反碎片化策略的基石。
- 过小的 Page Block:导致不同迁移类型的页面混合得更细碎。例如,一个 2MB 的物理区域内可能混合了数个 64KB 的 Movable 和 Unmovable 块,这使得分配 2MB 大页几乎不可能。
- 过大的 Page Block:导致内存区域属性转换困难。如果一个巨大的 Block 因为包含少量不可移动页而被锁定为 Unmovable,会浪费大量潜在的可移动空间。
4.2 性能权衡与测试数据
通常,Page Block Size 设置为与架构支持的最大 Huge Page 大小一致(如 x86 上的 2MB)是最佳实践。
下图展示了不同 Page Block 管理策略下的碎片化指数模拟对比:

(图示说明:在大内存分配场景下,匹配 HugePage 大小的 PageBlock 配置(如 2MB)能显著降低外部碎片指数,提高大页分配成功率)
5. 参考文献与环境信息
- Kernel Version: Linux 4.4.94
- Source Files :
mm/page_alloc.cinclude/linux/mmzone.hinclude/linux/pageblock-flags.h
- References :
- Gorman, Mel. "Understanding the Linux Virtual Memory Manager."
- Linux Kernel Documentation:
Documentation/vm/page_migration
图表数据基于模拟场景。*