2. 虚拟内存基础回顾:虚拟地址、物理地址、页表结构(单级、多级)、页表项格式
在深入页表遍历路径优化与 TLB shootdown 延迟降低之前,必须牢固掌握虚拟内存的底层基石。本章将系统回顾虚拟地址与物理地址的映射关系、页表的核心数据结构(单级与多级),以及页表项(PTE)的典型格式。这些概念是后续所有优化策略的数学与硬件基础。
2.1 虚拟地址与物理地址:解耦的基石
现代操作系统通过 内存管理单元(MMU) 实现虚拟地址(VA)到物理地址(PA)的转换。这种解耦带来了三大核心收益:
- 进程隔离:每个进程拥有独立的虚拟地址空间,无法直接访问其他进程的物理内存。
- 内存抽象:程序员可以操作远大于物理内存的虚拟空间(通过交换/分页)。
- 简化链接与加载:程序无需关心物理内存的实际布局,链接器只需处理连续的虚拟地址。
地址转换的基本流程如下:
- CPU 发出虚拟地址
VA。 - MMU 将
VA拆分为 虚拟页号(VPN) 和 页内偏移(Offset)。 - MMU 通过页表将
VPN转换为 物理页号(PPN)。 - 最终物理地址
PA = (PPN << PAGE_SHIFT) | Offset。
2.2 页表结构:从单级到多级
页表是存储 VPN→PPN 映射关系的数据结构。随着地址空间增大,单级页表面临巨大的内存浪费问题,多级页表成为主流。
2.2.1 单级页表(线性页表)
单级页表是一个线性数组,以 VPN 为索引直接查找 PTE。假设虚拟地址空间为 32 位(4 GiB),页大小为 4 KiB,则 VPN 占 20 位,页表项数为 2^20 = 1,048,576。若每项 4 字节,页表大小为 4 MiB。
| 特性 | 单级页表 | 多级页表(4 级) |
|---|---|---|
| 页表项数量 | 固定为 2^VPN_bits | 按需分配,仅分配使用的页目录 |
| 内存占用(空进程) | 4 MiB(32 位) | ~4 KiB(仅根页表) |
| 遍历次数(TLB miss) | 1 次内存访问 | 4 次内存访问(4 级) |
| 灵活性 | 低,必须连续物理内存 | 高,支持稀疏地址空间 |
2.2.2 多级页表(以 x86-64 4 级页表为例)
x86-64 使用 4 级页表结构:PML4(Page Map Level 4)、PDPT(Page Directory Pointer Table)、PD(Page Directory)、PT(Page Table)。48 位虚拟地址被拆分为 5 个部分:
- PML4 索引(9 位):选择 PML4 表中的一项,指向 PDPT 基址。
- PDPT 索引(9 位):选择 PDPT 表中的一项,指向 PD 基址。
- PD 索引(9 位):选择 PD 表中的一项,指向 PT 基址。
- PT 索引(9 位):选择 PT 表中的一项,得到 PTE(包含 PPN)。
- Offset(12 位):页内偏移。
每级页表大小为 2^9 * 8 字节 = 4 KiB,恰好等于一个物理页。这种设计使得页表本身可以按需分页,极大节省内存。
2.3 页表项(PTE)格式
页表项是页表的基本单元,包含物理页号(PPN)和一系列标志位。不同架构的 PTE 格式略有差异,但核心字段高度相似。以下以 x86-64 为例:
| 位域 | 宽度 | 名称 | 描述 |
|---|---|---|---|
| 0 | 1 | P (Present) | 页是否在物理内存中 |
| 1 | 1 | R/W (Read/Write) | 0=只读,1=可读写 |
| 2 | 1 | U/S (User/Supervisor) | 0=仅内核,1=用户态可访问 |
| 3 | 1 | PWT (Page Write-Through) | 缓存写策略:0=写回,1=写通 |
| 4 | 1 | PCD (Page Cache Disable) | 禁止该页的缓存 |
| 5 | 1 | A (Accessed) | 硬件置位,表示页被访问过 |
| 6 | 1 | D (Dirty) | 硬件置位,表示页被写入过 |
| 7 | 1 | PS (Page Size) | 0=4 KiB,1=大页(2 MiB/1 GiB) |
| 8 | 1 | G (Global) | 全局页,TLB 刷新时不被清除 |
| 11:9 | 3 | Ignored | 软件可用位(如用于页迁移、NUMA 信息) |
| 51:12 | 40 | PPN (Physical Page Number) | 物理页号(物理地址的高 40 位) |
| 62:52 | 11 | Reserved / Ignored | 保留位(必须为 0)或软件自定义 |
| 63 | 1 | NX (No-Execute) | 禁止执行该页的代码 |
2.4 页表遍历的硬件加速:TLB
多级页表遍历需要多次内存访问(4 级页表需要 4 次),这会导致严重的性能开销。转译后备缓冲器(TLB) 是 MMU 内部的高速缓存,用于缓存最近使用的 VA→PA 映射。
- TLB 命中:一次地址转换仅需 1 个时钟周期。
- TLB 未命中:硬件页表遍历器(Page Table Walker)自动执行 4 次内存访问,耗时数十到数百个时钟周期。
TLB 的覆盖范围(Coverage)取决于 TLB 项数和页面大小。例如,64 项 TLB 映射 4 KiB 页,仅覆盖 256 KiB;若使用 2 MiB 大页,则覆盖 128 MiB。这正是 大页(Huge Pages) 优化的核心动机。
2.5 本章小结
- 虚拟地址 通过 MMU 和页表转换为 物理地址,实现进程隔离与内存抽象。
- 多级页表(如 x86-64 4 级)解决了单级页表的内存浪费问题,但增加了遍历深度。
- 页表项(PTE) 包含 PPN 和关键标志位(P、R/W、U/S、A、D、NX 等),是硬件与软件交互的契约。
- TLB 是页表遍历的硬件缓存,其命中率直接影响系统性能。大页和 TLB 预取是常见的优化手段。