多级页表设计:结构、优势与硬件实现
多级页表是现代操作系统虚拟内存管理的核心机制。它通过将线性页表拆分为多个层级,解决了单级页表连续占用大块物理内存的问题,同时支持按需分配页表项,显著降低内存开销。本节将深入分析多级页表的通用结构、x86-64 的四级页表实现以及 ARMv8-A 的页表层级设计。
多级页表的结构与优势
单级页表(线性页表)需要为整个虚拟地址空间预分配一个连续的页表数组。例如,在 64 位系统中,若页大小为 4KB,页表项大小为 8 字节,则单级页表需要 252 × 8 字节的连续物理内存,这显然不可行。多级页表将虚拟地址划分为多个索引字段,每一级索引指向下一级页表的基地址,形成树状结构。
- 按需分配:只有实际使用的虚拟地址范围才需要分配页表页,未使用的区域对应的页表页可以完全省略。
- 连续内存需求降低:每级页表本身只占用一个物理页框(通常 4KB),不需要大块连续物理内存。
- 共享与保护:不同进程可以共享高几级页表(如内核空间),减少内存占用并简化上下文切换。
- 支持大页:通过跳过中间层级,可以直接映射大页(2MB、1GB),减少 TLB 压力。
下图展示了一个典型的三级页表结构,虚拟地址被划分为三级索引和页内偏移:
x86-64 四级页表详解
x86-64 架构采用四级页表(PML4、PDPT、PD、PT),支持 48 位虚拟地址空间。页表层级由 CR3 寄存器指向顶级页表基地址。每个页表页包含 512 个 8 字节条目,覆盖 4KB 物理页框。
| 层级 | 名称 | 索引位数 | 条目数 | 覆盖范围 |
|---|---|---|---|---|
| L4 | PML4 (Page Map Level 4) | 9 bit | 512 | 512 GB |
| L3 | PDPT (Page Directory Pointer Table) | 9 bit | 512 | 1 GB |
| L2 | PD (Page Directory) | 9 bit | 512 | 2 MB |
| L1 | PT (Page Table) | 9 bit | 512 | 4 KB |
虚拟地址格式为:[47:39] PML4 索引 | [38:30] PDPT 索引 | [29:21] PD 索引 | [20:12] PT 索引 | [11:0] 页内偏移。硬件 MMU 自动遍历这四级页表,若某级条目为空(未分配),则触发缺页异常。
下图展示了 x86-64 四级页表的完整翻译路径:
ARMv8-A 页表层级
ARMv8-A 架构支持 4KB、16KB 和 64KB 页大小,页表层级数根据页大小和虚拟地址宽度动态调整。典型配置为 4KB 页、48 位虚拟地址,使用四级页表(L0/L1/L2/L3)。与 x86-64 不同,ARMv8-A 的页表基地址寄存器为 TTBR0_EL1(用户空间)和 TTBR1_EL1(内核空间),支持独立的地址空间配置。
| 层级 | 名称 | 粒度 | 覆盖范围(4KB 页) | 特殊功能 |
|---|---|---|---|---|
| L0 | Page Table (PGD) | 512 条目 | 512 GB | 仅用于 48 位地址空间 |
| L1 | Page Table (PUD) | 512 条目 | 1 GB | 支持 1GB 大页 |
| L2 | Page Table (PMD) | 512 条目 | 2 MB | 支持 2MB 大页 |
| L3 | Page Table (PTE) | 512 条目 | 4 KB | 最终页表项 |
ARMv8-A 页表项格式与 x86-64 有显著差异:
- 描述符类型:每个条目包含类型位(block/table/page),block 条目直接映射大页,table 条目指向下一级页表。
- 访问权限:通过 AP[2:1] 字段控制用户/内核访问,与 x86-64 的 U/S 位类似但更灵活。
- 内存属性:AttrIndx[2:0] 指向 MAIR(Memory Attribute Indirection Register)中的属性配置,支持缓存策略、共享属性等。
- 非安全访问:NS 位用于 TrustZone 安全扩展,控制非安全世界访问权限。
- 页表基地址寄存器:ARM 使用 TTBR0/TTBR1 分离用户/内核,x86 使用 CR3 单一基址。
- 大页支持:ARM 在 L1/L2 级直接支持 block 条目,x86 在 PD/PDPT 级支持大页。
- 页表遍历缓存:ARM 有 TLB 和微 TLB(micro TLB)两级缓存,x86 使用 Paging-Structure Caches。
- 地址空间标识符:ARM 支持 ASID(Address Space ID)避免上下文切换时 TLB 刷全。
下图展示了 ARMv8-A 四级页表的遍历过程及与 x86-64 的对比:
PAGE_WALKS 事件、ARM 的 L1D_TLB_REFILL 事件)可以量化每级页表的访问次数,帮助定位是页表层级过深还是 TLB 容量不足导致的问题。