3. 多级页表结构:x86-64 四级页表
x86-64 架构采用四级页表结构,将线性地址逐级翻译为物理地址。这种层级设计在支持 48 位虚拟地址空间(256 TB)的同时,通过按需建立页表项来节省内存。四级页表由 PML4、PDPT、PD、PT 组成,每一级负责从线性地址中提取对应的索引字段,最终定位到 4 KB 物理页框。
3.1 四级页表层级划分
线性地址(48 位)被划分为 5 个字段:4 个页表索引(各 9 位)和 1 个页内偏移(12 位)。每个索引对应一级页表,页表本身占用一个 4 KB 页框,包含 512 个 8 字节的页表项(PTE)。
| 层级 | 全称 | 索引位 | 页表项数 | 作用 |
|---|---|---|---|---|
| PML4 | Page Map Level 4 | 47:39 | 512 | 指向 PDPT 页框 |
| PDPT | Page Directory Pointer Table | 38:30 | 512 | 指向 PD 页框 |
| PD | Page Directory | 29:21 | 512 | 指向 PT 页框 |
| PT | Page Table | 20:12 | 512 | 指向 4 KB 物理页框 |
关键指标: 四级页表最多可映射 5124 × 4 KB = 248 字节 = 256 TB 虚拟地址空间。每个进程拥有独立的 PML4 基址(CR3 寄存器),实现进程间地址空间隔离。
3.2 线性地址到物理地址的翻译流程
地址翻译由 MMU 硬件自动完成,每次内存访问最多需要 4 次页表遍历(若 TLB 缺失)。以下为完整翻译步骤:
- CR3 → PML4: 从 CR3 寄存器读取 PML4 页框基址,结合线性地址 [47:39] 索引,读取 PML4E。
- PML4E → PDPT: 检查 PML4E 的 Present 位(位 0),若为 1 则取出 PDPT 页框基址,结合 [38:30] 索引读取 PDPTE。
- PDPTE → PD: 检查 PDPTE 的 Present 位,取出 PD 页框基址,结合 [29:21] 索引读取 PDE。
- PDE → PT: 检查 PDE 的 Present 位,取出 PT 页框基址,结合 [20:12] 索引读取 PTE。
- PTE → 物理地址: 检查 PTE 的 Present 位,取出 4 KB 物理页框基址,拼接页内偏移 [11:0] 得到最终物理地址。
性能提示: 每次页表遍历涉及 4 次内存读取(PML4E、PDPTE、PDE、PTE)。TLB 缺失时,这 4 次访问会显著增加访存延迟(约 100–200 个 CPU 周期)。多级页表缓存(Paging-Structure Caches)可缓存中间页表项,减少遍历深度。
3.3 页表项格式
每个页表项(PTE)为 8 字节(64 位),包含物理页框基址(高位)和属性标志位(低位)。不同层级(PML4E、PDPTE、PDE、PTE)的格式基本一致,但部分位(如 PS 位)在 PD 和 PDPT 层级有特殊含义。
| 位域 | 宽度 | 名称 | 说明 |
|---|---|---|---|
| 63:12 | 52 | 物理页框基址 | 4 KB 对齐的物理地址高 52 位(x86-64 实际使用 40 位) |
| 11:9 | 3 | Ignored (AVL) | 操作系统可用位,硬件忽略 |
| 8 | 1 | G (Global) | 全局页标志,若置位则 TLB 刷新时保留该条目 |
| 7 | 1 | PS (Page Size) | 仅在 PDE 和 PDPTE 中有效:1 表示大页(2 MB / 1 GB) |
| 6 | 1 | D (Dirty) | 脏位,表示页框已被写入(由硬件置位) |
| 5 | 1 | A (Accessed) | 访问位,表示页框已被读取或写入(由硬件置位) |
| 4 | 1 | PCD (Cache Disable) | 页级缓存禁用,用于 MMIO 或非缓存内存区域 |
| 3 | 1 | PWT (Write-Through) | 页级写透缓存策略 |
| 2 | 1 | U/S (User/Supervisor) | 0=超级用户权限,1=用户态可访问 |
| 1 | 1 | R/W (Read/Write) | 0=只读,1=读写 |
| 0 | 1 | P (Present) | 存在位:0 表示页框不在内存中(触发缺页异常) |
常见陷阱: PS 位(位 7)仅在 PDE 和 PDPTE 中用于大页映射。若在 PML4E 或 PTE 中置位 PS,硬件行为未定义。操作系统必须确保大页映射时,对应页表项的低位(如偏移字段)被正确忽略。
3.4 四级页表结构 SVG 图
下图展示了线性地址如何通过四级页表逐级翻译为物理地址。每个页表项指向下一级页表的基址,最终 PTE 指向 4 KB 物理页框。
3.5 多级页表的内存节省原理
与单级页表(需连续存储 236 项,约 512 GB)相比,四级页表通过“按需分配”中间页表大幅降低内存占用。以下为典型场景对比:
| 场景 | 单级页表 | 四级页表 | 节省比例 |
|---|---|---|---|
| 空进程(仅内核映射) | 512 GB | ~20 KB(PML4 + 少量 PDPT/PD/PT) | 99.9999% |
| 4 GB 连续用户空间 | 512 GB | ~8 MB(PML4 + 512 PDPT + 512 PD + 512 PT) | 99.998% |
| 256 TB 全映射 | 512 GB | ~512 MB(所有页表项全部分配) | 99.9% |
核心结论: 四级页表以少量遍历开销(最多 4 次内存访问)换取巨大的内存节省。实际系统中,大多数进程仅使用少量页表项,多级结构使页表内存占用与进程实际使用的虚拟地址范围成正比。
3.6 页表项缓存与 TLB 的关系
TLB 缓存的是最终物理地址翻译结果(虚拟页号 → 物理页框号),而多级页表缓存(Paging-Structure Caches)缓存的是中间页表项(PML4E、PDPTE、PDE)。当 TLB 缺失时,MMU 首先查询这些中间缓存,若命中则可跳过部分页表遍历:
- PML4 缓存: 缓存最近使用的 PML4E,避免每次遍历都读取 PML4 页框。
- PDPT 缓存: 缓存 PDPTE,若命中则跳过 PML4 和 PDPT 两级访问。
- PD 缓存: 缓存 PDE,若命中则仅需读取 PTE 即可完成翻译。
优化方向: 多级页表缓存的命中率直接影响 TLB 缺失后的惩罚。操作系统通过大页映射(2 MB / 1 GB)减少页表层级,同时利用 Accessed 位和 Dirty 位优化页表项替换策略,可有效提升缓存命中率。