物理页分配机制与实现详解

物理页分配机制与实现详解

源码路径rk3588/kernel-6.1/mm/page_alloc.cmmzone.cvmstat.c
内核版本:Linux 6.1(RK3588 / ARM64)
文档目录linuxDoc/mm/


目录


一、原理

1.1 伙伴系统(Buddy Allocator)

物理内存按 2^order 个连续页 组成块管理:

  • order 0:单页(4KB,取决于 PAGE_SIZE
  • order n:2^n 页连续块
  • 分配:在对应 order 空闲链取块;若无则向更高 order 分裂
  • 释放:与 buddy 合并,若 buddy 也空闲则升阶

优点:O(log N) 分配/释放;缺点:外部碎片(有足够空闲页但无足够连续块)。

1.2 Zone 分层

每个 NUMA node(RK3588 UMA 通常仅 node 0)划分为多个 zone

Zone ARM64 典型用途
DMA32 低 4GB,32 位 DMA 设备
NORMAL 主内存
(CMA 区域) 页带 PageCMA,平时可迁移,CMA 分配时 pin

分配请求通过 zonelist 按策略遍历 zone(本地 node 优先、fallback 等)。

1.3 水位线(Watermark)

每个 zone 维护 min / low / high 三档空闲页阈值:

水位 行为
free > high 正常分配
free ≤ low 唤醒 kswapd 异步回收
free ≤ min 分配器在慢路径 同步 direct reclaim
仍不足 compaction → 可能 OOM

1.4 GFP 与迁移类型

gfp_t 指定分配上下文:是否可睡眠、是否 IO/FS、是否 DMA32、是否 可迁移(MIGRATE_MOVABLE) 等。

迁移类型(migratetype) 将空闲页分类(不可迁移、可迁移、可回收、CMA 等),避免不可移动内核数据阻塞 compaction。

1.5 Per-CPU 页缓存(PCP)

为降低 zone->lock 竞争,每个 CPU 有 per-cpu pageset:小 order 分配优先从本地列表取,批量 refill/drain。


二、实现方式

2.1 总入口:__alloc_pages()

1
2
3
4
5
6
7
8
9
10
11
12
13
struct page *__alloc_pages(gfp_t gfp, unsigned int order, int preferred_nid,
nodemask_t *nodemask)
{
// ...
prepare_alloc_pages(...);
page = get_page_from_freelist(alloc_gfp, order, alloc_flags, &ac);
if (likely(page))
goto out;
page = __alloc_pages_slowpath(alloc_gfp, order, &ac);
out:
// memcg charge, trace, kmsan ...
return page;
}

快路径get_page_from_freelist() 在水位允许时从 zonelist 取页。
慢路径__alloc_pages_slowpath() → direct reclaim、try_to_compact_pages、再次尝试 freelist,最后 __alloc_pages_may_oom()

2.2 prepare_alloc_pages

构建 struct alloc_context

  • 解析 preferred nid、nodemask(NUMA/cpuset)
  • 计算 alloc_flagsALLOC_WMARK_*ALLOC_CPUSET 等)
  • 选择起始 zoneref

2.3 get_page_from_freelist

对每个候选 zone:

  1. 检查 水位 + cpuset + spread
  2. 调用 rmqueue() 从 buddy 或 PCP 取页
  3. prep_new_page() 初始化页状态

失败则尝试下一个 zone 或降低 watermark 等级(ALLOC_NO_WATERMARKS 仅特殊 GFP)。

2.4 rmqueue 与伙伴合并

  • __rmqueue_smallest:从最小满足 order 的 free_area 取
  • expand():分裂大块
  • __free_one_page() / free_pages():释放时 buddy = pfn ^ (1 << order) 尝试合并

2.5 慢路径概要

1
2
3
4
5
__alloc_pages_slowpath
├─ wake_all_kswapds()
├─ __perform_reclaim() // direct reclaim
├─ try_to_compact_pages() // 需要连续物理页时
└─ __alloc_pages_may_oom()

2.6 初始化

阶段 函数 说明
zone 建立 free_area_init() 各 zone 的 free_area、水位
页进入 buddy memblock_free_all 间接 见 01 文档
PCP page_alloc_init() CPU hotplug 注册 page_alloc_cpu_online/dead

2.7 vmstat.c

维护 NR_FREE_PAGESNR_ALLOC_BATCH、per-zone LRU 统计等,供 /proc/vmstat/proc/zoneinfo 与回收逻辑读取。


三、关键数据结构与接口

结构/接口 说明
struct zone free_area[]、watermark、percpu pageset
struct free_area 按 order 的空闲链表
__alloc_pages 页分配核心
alloc_pages 包装,返回 page
__get_free_pages 返回内核虚拟地址(非 highmem)
free_pages / __free_pages 释放

order 上限MAX_ORDER(通常 11,即 4MB 块,与配置相关)。


四、RK3588 平台说明

  • 编解码/显示驱动大块 DMA 常需 高 orderCMA;buddy 高 order 失败时依赖 compaction(见 07 文档)。
  • __GFP_DMA32:限制从 DMA32 zone 分配,避免 32 位设备无法访问高物理地址。
  • CMA 页:带 PageCMA,普通 __alloc_pages 在无 CMA 标志时不应长期占用 CMA 池(由 migratetype 与 gfp 约束)。

五、调试与观测

接口/参数 内容
/proc/buddyinfo 各 zone 各 order 空闲块数
/proc/pagetypeinfo 迁移类型分布
/proc/zoneinfo 水位线与统计
min_free_kbytes sysctl,影响 min 水位
watermark_scale_factor 影响 low/high 计算

tracepoint:trace_mm_page_alloc


附录:源码索引

主题 文件 约略行号
__alloc_pages page_alloc.c 5596
page_alloc_init page_alloc.c 8733
free_area_init page_alloc.c 8393
zone 统计 vmstat.c 全文

文章互动

阅读 --

留言

0 条留言

正在加载留言…