3. TLB 基础:作用、结构与缺失/命中
TLB(Translation Lookaside Buffer,转译后备缓冲器)是 CPU 内部一个容量极小但速度极快的硬件缓存,专门用于缓存最近使用的虚拟地址 → 物理地址的页表项(PTE)。它的存在直接决定了虚拟内存系统的性能上限。
3.1 TLB 的核心作用
在没有 TLB 的情况下,每次内存访问都需要经历一次完整的页表遍历(Page Walk),即从顶级页目录开始逐级查找,直到找到最终的物理页框号。对于 4 级页表(x86_64 默认配置),一次页表遍历需要 4 次内存访问,这会导致性能急剧下降。
TLB 的作用可以概括为以下三点:
- 加速地址转换:将虚拟页号(VPN)直接映射到物理页框号(PFN),避免重复的页表遍历。
- 降低访存延迟:TLB 命中时,地址转换延迟通常为 1 个 CPU 周期;而一次完整的页表遍历可能需要 100+ 个周期。
- 减少内存带宽占用:页表遍历会占用内存总线带宽,TLB 命中可以完全消除这部分开销。
3.2 TLB 的结构类型
TLB 的硬件结构决定了其查找速度、功耗和容量上限。根据相联度(Associativity),TLB 主要分为以下三种结构:
| 结构类型 | 相联度 | 查找方式 | 典型容量 | 功耗/延迟 | 适用场景 |
|---|---|---|---|---|---|
| 全相联 TLB | 完全 | 并行比较所有条目 | 32~64 项 | 高功耗、低延迟 | L1 TLB(指令 TLB) |
| 组相联 TLB | 4~8 路 | 索引 + 组内并行比较 | 256~1024 项 | 中等功耗、中等延迟 | L1/L2 TLB(数据 TLB) |
| 直接映射 TLB | 1 路 | 直接索引 | 64~256 项 | 低功耗、高冲突缺失率 | 较少使用(已被组相联替代) |
3.2.1 全相联 TLB
全相联 TLB 允许任意虚拟页号映射到 TLB 中的任意位置。查找时,硬件将输入的 VPN 与 TLB 中所有条目的 VPN 标签同时进行比较。这种结构具有最低的冲突缺失率,但比较器数量随条目数线性增长,导致功耗和面积急剧上升,因此通常只用于容量极小的 L1 TLB。
3.2.2 组相联 TLB
组相联 TLB 是当前主流 CPU 中最常见的结构。它将 TLB 划分为若干组(Set),每个组内包含若干路(Way)。查找时,硬件首先根据 VPN 的索引位定位到具体的组,然后在该组内并行比较所有路的标签。组相联结构在容量和查找速度之间取得了良好的平衡。
3.3 TLB 缺失与命中
TLB 的命中与缺失是衡量系统内存性能的核心指标。理解其判定流程和代价,是优化页表遍历路径的前提。
3.3.1 TLB 命中流程
当 CPU 发出一个虚拟地址时,TLB 控制器执行以下步骤:
- 提取 VPN:从虚拟地址中提取虚拟页号(VPN)。
- 索引定位:对于组相联 TLB,使用 VPN 的索引位定位到具体的组。
- 标签比较:将 VPN 的标签位与组内所有路的标签进行并行比较。
- 权限检查:如果标签匹配,进一步检查访问权限(读/写/执行)是否允许。
- 返回 PFN:权限检查通过后,TLB 输出物理页框号(PFN),与页内偏移拼接形成物理地址。
3.3.2 TLB 缺失处理
当 TLB 中不存在匹配的条目时,发生 TLB 缺失。缺失处理由硬件或软件完成:
| 缺失类型 | 触发条件 | 处理方式 | 典型代价 |
|---|---|---|---|
| TLB 缺失(硬件遍历) | TLB 未命中 | 硬件页表遍历器(Page Walker)自动遍历页表 | 50~200 周期 |
| TLB 缺失(软件遍历) | TLB 未命中(罕见架构) | 触发异常,由操作系统遍历页表并更新 TLB | 数百~数千周期 |
| TLB 多级缺失 | L1 TLB 未命中 → L2 TLB 也未命中 | L2 TLB 缺失后触发页表遍历 | 100~300 周期 |
3.3.3 TLB 缺失的代价分析
TLB 缺失的代价不仅仅是额外的内存访问,还包括:
- 流水线停顿:CPU 在等待地址转换结果时,加载/存储指令无法继续执行。
- 页表遍历开销:4 级页表遍历需要 4 次内存读取,每次读取可能命中缓存(L1/L2/L3)或导致内存访问。
- TLB 填充延迟:遍历完成后,需要将新的 PTE 写入 TLB,这本身也需要时间。
- 替换污染:新条目可能替换掉后续即将用到的旧条目,导致后续缺失。
3.4 TLB 条目格式与关键字段
每个 TLB 条目(Entry)存储一个完整的页表项信息。典型的 TLB 条目包含以下字段:
| 字段 | 宽度(典型值) | 说明 |
|---|---|---|
| VPN 标签 | 20~36 位 | 虚拟页号的高位部分,用于与输入 VPN 比较 |
| PFN | 20~36 位 | 物理页框号,与页内偏移拼接形成物理地址 |
| 权限位 | 3~5 位 | 读 (R)、写 (W)、执行 (X)、用户/内核 (U/S) |
| 属性位 | 2~4 位 | 全局 (G)、脏 (D)、访问 (A)、缓存策略 (PCD/PWT) |
| ASID/PCID | 8~16 位 | 地址空间标识符 / 进程上下文标识符,用于进程隔离 |
3.5 多级 TLB 层次结构
现代 CPU 通常采用多级 TLB 结构,以平衡速度与容量:
- L1 TLB:容量最小(32~64 项),速度最快(1 周期),通常分为指令 TLB(ITLB)和数据 TLB(DTLB)。
- L2 TLB:容量较大(256~2048 项),速度中等(2~5 周期),统一缓存指令和数据。
- L3 TLB:部分高端 CPU(如 AMD Zen 系列)引入 L3 TLB,容量可达 4096 项以上。
多级 TLB 的命中率通常遵循以下规律:
L1 TLB 命中率:95%~99%
L2 TLB 命中率(L1 缺失后):80%~95%
L3 TLB 命中率(L2 缺失后):50%~80%
整体 TLB 命中率:99.5%~99.9%
即使整体命中率高达 99.9%,在每秒数十亿次内存访问的 CPU 中,仍然意味着每秒数百万次 TLB 缺失,因此 TLB 缺失优化仍然是系统性能的关键战场。