物理内存组织架构与Buddy分配器关系分析
在Linux内核中,物理内存的管理是一个分层级的复杂系统。为了高效地应对不同硬件架构(如NUMA)和不同的内存需求(如DMA访问限制),Linux建立了严密的物理内存组织架构。而Buddy分配器(伙伴算法)则是这个架构中用于管理空闲页面的核心机制。本文将分析物理内存的组织方式以及Buddy分配器是如何嵌入其中发挥作用的。
引导内存分配器(memblock):启动早期使用,记录物理内存与保留区;系统起来后把可用内存交给 buddy。
zone:物理内存的分区视图(DMA/NORMAL/MOVABLE),是 buddy 运行的“管理边界”。
buddy 分配器:每个 zone 内的页级分配器,提供物理页(连续页)给上层。
slab/SLUB:对象级分配器,从 buddy 申请页,然后切成对象缓存给 kmalloc 等使用。
一句话:memblock 早期 → buddy 管页(按 zone) → slab 管对象。
一、物理内存组织架构
Linux内核采用Node(节点) -> Zone(区域) -> Page(页)的三级结构来描述物理内存。
1. 节点 (Node)
在NUMA(非一致性内存访问)架构中,内存被划分为多个节点。每个CPU都有其本地内存节点,访问速度最快。
- 数据结构:
struct pglist_data(typedef为pg_data_t)。 - 作用:它是内存管理的最高层级容器。
2. 区域 (Zone)
为了适应硬件限制,每个Node内的内存被进一步划分为不同的区域。
- 数据结构:
struct zone。 - 常见的Zone包括:
ZONE_DMA/ZONE_DMA32:用于旧式硬件或32位设备进行DMA操作的低地址内存。ZONE_NORMAL:内核可以直接映射的普通内存区域。ZONE_HIGHMEM:32位系统中无法直接映射的高端内存。ZONE_MOVABLE:用于可热插拔或通过内存碎片整理可移动的内存。
3. 页 (Page)
物理内存管理的最小单位,通常为4KB、8KB或更大。
- 数据结构:
struct page。 - 所有的物理页都在内存映射数组
mem_map中有一个对应的描述符。
二、Buddy分配器 (伙伴算法)
Buddy分配器是Linux内核中用于解决外部碎片问题的一种物理内存管理算法。它不直接管理单个字节,而是页框(Page Frame)为基本单位。
核心原理
Buddy分配器将空闲内存分为不同阶(Order)的块链表进行管理。
- 阶 (Order):表示内存块包含2 n 2^n2n个连续物理页。通常n nn的范围是 0 到
MAX_ORDER-1(默认为11,即最大支持2 10 = 1024 2^{10}=1024210=1024个页的连续块,约4MB)。 - 分配:当请求分配2 k 2^k2k个页时,检查第k kk阶是否有空闲块。如果有,直接分配;如果没有,则查找k + 1 k+1k+1阶,将2 k + 1 2^{k+1}2k+1的块分裂为两个2 k 2^k2k的块(互为伙伴),一个分配,一个插入第k kk阶链表。
- 释放:释放内存块时,检查其物理地址相邻的“伙伴”块是否也空闲。如果空闲,则合并成更大的块,并向高阶递归合并,直到无法合并为止。
三、组织架构与Buddy分配器的关系
Buddy分配器并非独立存在,而是直接“寄生”在物理内存组织架构的Zone(区域)层级之上。
1. Buddy 是 Zone 的一部分
Buddy分配器的数据结构直接定义在struct zone中。
structzone{/* ... 前面的统计字段 ... *//* free areas of different sizes */structfree_areafree_area[MAX_ORDER];/* ... */};- 每个
struct zone都有自己独立的一套free_area数组。 - 这意味着:内存分配是在特定的Zone中进行的。例如,申请DMA内存时,内核会明确在
ZONE_DMA的Buddy系统中查找空闲页。
2.free_area数组是连接点
free_area[MAX_ORDER]数组是物理内存组织与Buddy算法的物理连接点。
structfree_area{structlist_headfree_list[MIGRATE_TYPES];// 空闲块链表unsignedlongnr_free;// 该阶空闲块的数量};- 数组下标:对应Buddy算法的阶 (Order)。
free_area[0]存放单页块,free_area[1]存放2页块,以此类推。 - MIGRATE_TYPES:为了解决内存碎片问题(反碎片机制),同一阶的空闲块还会根据迁移类型(如
MIGRATE_UNMOVABLE,MIGRATE_MOVABLE)挂入不同的链表。
3. 工作流示例
当内核调用alloc_pages(gfp_mask, order)申请内存时:
- 确定Node和Zone:根据
gfp_mask(如GFP_KERNEL)和内存策略,内核决定在哪个Node的哪个Zone(如ZONE_NORMAL)进行分配。 - 访问Zone的Buddy系统:内核锁定该Zone的自旋锁,访问该Zone结构体中的
free_area数组。 - 查找空闲块:从
free_area[order]开始查找。如果为空,则遍历order+1,order+2… 直到MAX_ORDER-1。 - 分裂与服务:找到并分裂高阶块(如果需要),更新
free_area链表和nr_free计数,返回物理页。
4. 总结
| 层级 | 职责 | 与Buddy的关系 |
|---|---|---|
| Node | 解决NUMA访问延迟 | 包含多个Zone,间接管理多个Buddy实例。 |
| Zone | 解决硬件寻址限制 | Buddy分配器的宿主。每个Zone维护独立的Buddy系统来管理自己的空闲页。 |
| Page | 最小物理单位 | Buddy分配器的管理对象。Buddy系统负责将Page组织成2 n 2^n2n的链表。 |
综上所述,物理内存组织架构提供了硬件抽象的容器(Node/Zone),而Buddy分配器则是填充在这些容器中的管理逻辑,两者结合实现了高效、有序的物理内存分配。