2. 标准4KB页表详解:页表项(PTE)结构、页表遍历过程、TLB缓存机制

在 x86-64 架构中,标准页大小为 4KB,这是操作系统内存管理最基础的粒度。理解 4KB 页表的工作原理,是掌握大页技术的前提。本节将深入剖析页表项(PTE)的二进制布局、四级页表遍历的硬件路径,以及 TLB 如何加速地址转换。

2.1 页表项(PTE)结构

每个页表项(Page Table Entry, PTE)是一个 64 位(8 字节)的数据结构,用于描述一个虚拟页到物理页的映射关系,并携带权限与状态信息。在 x86-64 四级页表层次中,各级页表的表项结构基本一致,但只有最后一级(PT)的 PTE 指向物理页帧。

位域 宽度(位) 名称 说明
63:52 12 IGN / PK 忽略位或保护密钥(Protection Key)
51:12 40 物理页帧号(PFN) 物理地址的高 40 位,与 12 位页内偏移拼接得到完整物理地址
11:9 3 AVL 操作系统可用位(如用于页面换出标志)
8 1 G 全局页标志(Global),置位后 TLB 刷新时不被清除
7 1 PAT 页属性表索引(Page Attribute Table)
6 1 D 脏位(Dirty),页面被写入时硬件置位
5 1 A 访问位(Accessed),页面被读/写时硬件置位
4:3 2 PCD / PWT 缓存控制位(Cache Disable / Write-Through)
2 1 U/S 用户/超级用户权限(User/Supervisor)
1 1 R/W 读写权限(Read/Write)
0 1 P 存在位(Present),为 0 时触发缺页异常
关键位解读: 存在位(P)是页表遍历的“门禁”——如果 P=0,MMU 立即触发缺页异常(#PF),由内核处理。脏位(D)和访问位(A)由硬件自动维护,操作系统利用它们实现页面置换算法(如 LRU 近似)和写回策略。
PTE 64位结构布局 63:52 (IGN/PK) 51:12 物理页帧号 (PFN) 11:9 AVL G PAT D A U/S R/W P 12位 40位 3位 1位 1位 1位 1位 1位 1位 1位 物理地址 = PFN << 12 + 页内偏移(虚拟地址低12位)

2.2 页表遍历过程:四级页表硬件路径

x86-64 使用 4 级页表(PML4 → PDPT → PD → PT)将 48 位虚拟地址转换为物理地址。MMU(内存管理单元)完全由硬件完成遍历,操作系统只需维护页表结构。虚拟地址被划分为 5 个部分:

  • Bits 47:39 — PML4 索引(9 位,512 项)
  • Bits 38:30 — PDPT 索引(9 位,512 项)
  • Bits 29:21 — PD 索引(9 位,512 项)
  • Bits 20:12 — PT 索引(9 位,512 项)
  • Bits 11:0 — 页内偏移(12 位,4KB 内寻址)
遍历步骤:
  1. MMU 从 CR3 寄存器读取 PML4 页表的物理基地址。
  2. 以虚拟地址 [47:39] 为索引,在 PML4 表中找到对应表项(PML4E),获取下一级 PDPT 页表的物理地址。
  3. 以 [38:30] 为索引,在 PDPT 表中找到 PDPTE,获取 PD 页表物理地址。
  4. 以 [29:21] 为索引,在 PD 表中找到 PDE,获取 PT 页表物理地址。
  5. 以 [20:12] 为索引,在 PT 表中找到 PTE,获取物理页帧号(PFN)。
  6. 将 PFN 左移 12 位,加上虚拟地址低 12 位偏移,得到最终物理地址。
四级页表硬件遍历路径 PML4索引 [47:39] PDPT索引 [38:30] PD索引 [29:21] PT索引 [20:12] 页内偏移 [11:0] PML4 PDPT PD PT 物理页帧 CR3 → PML4基址 → 索引[47:39] → PML4E → PDPT基址 → 索引[38:30] → PDPTE → PD基址 → 索引[29:21] → PDE → PT基址 → 索引[20:12] → PTE → PFN + 偏移[11:0] → 物理地址
性能代价: 每次地址转换需要 4 次内存访问(读 PML4E、PDPTE、PDE、PTE)。如果 TLB 未命中,一次内存访问可能因页表遍历产生 4 次额外的 DRAM 访问,延迟增加数十纳秒。这正是大页(2MB/1GB)减少页表层级、降低 TLB 未命中开销的根本原因。

2.3 TLB 缓存机制

TLB(Translation Lookaside Buffer)是 CPU 内部的硬件缓存,专门存储最近使用的虚拟地址到物理地址的转换结果。TLB 的核心目标是避免每次内存访问都走完整的四级页表遍历。

2.3.1 TLB 结构

属性 典型值(x86-64) 说明
L1 D-TLB 64 ~ 128 项 数据访问专用,4KB 页,4 路组相联
L1 I-TLB 64 ~ 128 项 指令访问专用,4KB 页,4 路组相联
L2 TLB 512 ~ 2048 项 统一数据/指令,4KB/2MB 页混合
TLB 命中延迟 1 ~ 2 个 CPU 周期 几乎无开销
TLB 未命中延迟 50 ~ 200 个 CPU 周期 包含页表遍历和内存访问

2.3.2 TLB 刷新与一致性

当操作系统修改页表(如解除映射、切换进程)时,必须使对应的 TLB 项失效,否则 CPU 可能使用过时的转换结果。x86-64 提供以下刷新机制:

  • INVLPG 指令: 使单个虚拟地址对应的 TLB 项失效,粒度最细。
  • MOV CR3: 写入 CR3 寄存器会刷新所有非全局 TLB 项(G 位为 0 的项)。进程切换时内核通过此操作刷新 TLB。
  • PCID(Process Context ID): 现代 CPU 支持 PCID,允许为不同进程的 TLB 项打标签,避免进程切换时完全刷新 TLB,显著降低上下文切换开销。
TLB 缓存命中与未命中流程 CPU 发出虚拟地址 TLB 命中? 直接获取物理地址 TLB 未命中 硬件页表遍历 更新 TLB 缓存 TLB 命中:1~2 周期;TLB 未命中:50~200 周期(含 4 次内存访问)

2.4 标准4KB页表的性能瓶颈

三大瓶颈:
  • TLB 覆盖范围小: 以 64 项 L1 D-TLB 为例,仅能覆盖 64 × 4KB = 256KB 内存。对于数据库、HPC 等大内存工作负载,TLB 未命中率极高。
  • 页表遍历开销: 每次 TLB 未命中需要 4 次内存访问,若页表本身不在 CPU 缓存中,将导致显著的延迟。
  • 页表占用内存: 每个进程独立维护页表,4KB 页表本身占用大量物理内存(例如,1GB 虚拟地址空间需要约 2MB 页表)。