2. 虚拟内存基础回顾:虚拟地址、物理地址、页表结构(单级、多级)、页表项格式

在深入页表遍历路径优化与 TLB shootdown 延迟降低之前,必须牢固掌握虚拟内存的底层基石。本章将系统回顾虚拟地址与物理地址的映射关系、页表的核心数据结构(单级与多级),以及页表项(PTE)的典型格式。这些概念是后续所有优化策略的数学与硬件基础。

2.1 虚拟地址与物理地址:解耦的基石

现代操作系统通过 内存管理单元(MMU) 实现虚拟地址(VA)到物理地址(PA)的转换。这种解耦带来了三大核心收益:

  • 进程隔离:每个进程拥有独立的虚拟地址空间,无法直接访问其他进程的物理内存。
  • 内存抽象:程序员可以操作远大于物理内存的虚拟空间(通过交换/分页)。
  • 简化链接与加载:程序无需关心物理内存的实际布局,链接器只需处理连续的虚拟地址。
关键指标: 在 x86-64 架构中,虚拟地址宽度为 48 位(高 16 位为符号扩展),可寻址 256 TiB 的虚拟空间;物理地址宽度通常为 48 位或 52 位,最大支持 4 PiB 物理内存。

地址转换的基本流程如下:

  1. CPU 发出虚拟地址 VA。
  2. MMU 将 VA 拆分为 虚拟页号(VPN) 和 页内偏移(Offset)。
  3. MMU 通过页表将 VPN 转换为 物理页号(PPN)。
  4. 最终物理地址 PA = (PPN << PAGE_SHIFT) | Offset。
虚拟地址到物理地址转换流程 虚拟地址 → 物理地址转换流程 虚拟地址 (VA) VPN (虚拟页号) Offset (页内偏移) 页表 PPN (物理页号) 物理地址 (PA)

2.2 页表结构:从单级到多级

页表是存储 VPN→PPN 映射关系的数据结构。随着地址空间增大,单级页表面临巨大的内存浪费问题,多级页表成为主流。

2.2.1 单级页表(线性页表)

单级页表是一个线性数组,以 VPN 为索引直接查找 PTE。假设虚拟地址空间为 32 位(4 GiB),页大小为 4 KiB,则 VPN 占 20 位,页表项数为 2^20 = 1,048,576。若每项 4 字节,页表大小为 4 MiB。

核心问题: 单级页表必须为整个虚拟地址空间预分配连续物理内存。即使进程只使用少量内存(如 1 MiB),页表仍占用 4 MiB。对于 64 位系统,单级页表将大到无法接受(2^48 * 8 字节 = 2 PiB)。
单级页表 vs 多级页表(x86-64 4 级页表)
特性 单级页表 多级页表(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,恰好等于一个物理页。这种设计使得页表本身可以按需分页,极大节省内存。

x86-64 4级页表遍历路径 x86-64 4 级页表遍历路径 PML4 (9 bit) PDPT (9 bit) PD (9 bit) PT (9 bit) Offset (12 bit) PML4 表 PDPT 表 PD 表 PT 表 PPN 每级页表大小为 4 KiB(512 项 × 8 字节),恰好占一个物理页

2.3 页表项(PTE)格式

页表项是页表的基本单元,包含物理页号(PPN)和一系列标志位。不同架构的 PTE 格式略有差异,但核心字段高度相似。以下以 x86-64 为例:

x86-64 页表项(PTE)格式(8 字节)
位域 宽度 名称 描述
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) 禁止执行该页的代码
优化关注点: A/D 位由硬件自动置位,但软件(操作系统)负责清零。在页表遍历优化中,Accessed 位 可用于近似工作集检测,Dirty 位 用于决定是否将页写回磁盘。NX 位是硬件级安全机制,防止代码注入攻击。

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) 优化的核心动机。

TLB 加速页表遍历 TLB 加速页表遍历 CPU TLB Page Table Walker 内存 TLB 命中:1 周期;TLB 未命中:Walker 遍历 4 级页表,耗时 ~100 周期

2.5 本章小结

  • 虚拟地址 通过 MMU 和页表转换为 物理地址,实现进程隔离与内存抽象。
  • 多级页表(如 x86-64 4 级)解决了单级页表的内存浪费问题,但增加了遍历深度。
  • 页表项(PTE) 包含 PPN 和关键标志位(P、R/W、U/S、A、D、NX 等),是硬件与软件交互的契约。
  • TLB 是页表遍历的硬件缓存,其命中率直接影响系统性能。大页和 TLB 预取是常见的优化手段。