Skip to main content

TLB

📅 2026-03-30 ✏️ 2026-03-30 CS
No related notes

1 · TLB#

https://en.wikipedia.org/wiki/Translation_lookaside_buffer

1.1 · S 什么场景#

现代 CPU 使用虚拟内存:每个进程看到的地址都是虚拟地址,必须通过页表(page table) 翻译成物理地址才能真正访问内存。

页表存在主存里,本身就是多级结构(x86-64 通常 4 级)。这意味着每次内存访问都要先做一次 page walk——沿着页表树走 4 次内存读——才能拿到物理地址,然后才去访问目标数据。

一次普通内存访问,变成了 5 次。

1.2 · C 什么冲突#

冲突在于:虚拟内存提供了隔离和灵活性,但 page walk 的代价让它变得不可接受地慢。

  • 想要隔离和安全:每个进程有独立地址空间,互不干扰
  • 想要性能:不希望每次内存访问都额外付出 4 次主存读取的延迟

如果每次访存都做完整 page walk,CPU 大部分时间花在”查地址”而不是”用数据”上。

1.3 · Q 什么问题#

1.3.1 · 1. TLB 是什么?#

TLB(Translation Lookaside Buffer)是 MMU 中的一个硬件缓存,缓存最近使用过的虚拟地址 → 物理地址映射。

  • 本质上是一个小型的、用 CAM(Content-Addressable Memory)实现的关联缓存
  • 输入虚拟页号(VPN),输出物理帧号(PFN)
  • 命中时只需 1 个时钟周期,完全在流水线内完成

1.3.2 · 2. TLB hit 和 TLB miss 分别发生什么?#

TLB hit:虚拟页号在 TLB 中找到对应条目,直接拿到物理帧号,拼上页内偏移即可访问物理内存。代价约 1 个周期。

TLB miss:TLB 中没有这个映射,需要做 page walk:

  1. 硬件(x86)或软件(MIPS)遍历多级页表
  2. 找到有效的页表项 → 把映射加载到 TLB,重试访问
  3. 如果页表中 present bit 也没设置 → 触发 page fault,由 OS 处理(可能要从磁盘换入页面)

TLB miss 的代价远大于普通 cache miss,因为 page walk 本身就需要多次内存访问。

1.3.3 · 3. TLB miss 由谁处理?#

三种方案:

方案代表架构特点
硬件管理x86(CR3 寄存器指向页表根)CPU 自动 walk 页表,对软件透明
软件管理MIPS, SPARCTLB miss 触发异常,由 OS 代码填充 TLB
固件管理Alpha(PALcode)类似软件管理,但由固件处理,允许不同 OS 用不同页表格式

x86 用硬件管理,好处是简单且快;软件管理的好处是灵活(OS 可以自定义页表格式和替换策略)。

1.3.4 · 4. TLB 的典型结构是什么样?#

现代 CPU 通常有多级 TLB,类似 L1/L2 cache 的分层:

  • L1 ITLB(指令)+ L1 DTLB(数据):小、快、低延迟
  • L2 TLB:统一的、更大的 TLB,L1 miss 后查这里

以 Intel Nehalem 为例:

  • L1 DTLB:64 条目(4 KiB 页),4 路组相联
  • L1 ITLB:128 条目(4 KiB 页),4 路组相联
  • L2 TLB:512 条目(4 KiB 页),4 路组相联,指令数据统一

1.3.5 · 5. 上下文切换时 TLB 怎么办?#

进程切换意味着地址空间变了,TLB 中旧进程的映射不再有效。最简单的做法是整体刷新(flush),但代价很高——新进程刚切进来时 TLB 全空,每次访存都是 miss。

优化手段:

  • ASID(Address Space Number):每个 TLB 条目带上地址空间标识,只有 ASID 匹配当前进程的条目才有效。切换时不需要 flush,只需切换 ASID
  • PCID(Process-Context Identifier, x86):Intel 从 Westmere 开始支持的 12-bit 标识符,允许 TLB 同时保留多个进程的映射
  • Global 页:标记为 global 的页(如内核映射)在切换时不被刷新

Linux 4.14 开始利用 PCID 避免不必要的 TLB flush,这在 Meltdown/Spectre 补丁(KPTI)后对性能尤为重要。

1.3.6 · 6. 大页(Huge Pages)为什么能减少 TLB miss?#

TLB 条目数量有限(通常几十到几百个)。如果页大小是 4 KiB,512 个 TLB 条目只能覆盖 2 MiB 的内存。

使用大页(x86 上 2 MiB 或 1 GiB)时:

  • 同样数量的 TLB 条目可以覆盖更大范围的内存
  • 32 个 2 MiB 大页条目就能覆盖 64 MiB
  • page walk 也更短(少一级页表)

适用场景:数据库、JVM、大内存工作集的应用。

1.3.7 · 7. TLB 与 CPU cache 的关系?#

TLB 的位置决定了 cache 使用物理地址还是虚拟地址:

  • 物理地址缓存(PIPT):每次访存先查 TLB 拿物理地址,再用物理地址查 cache。正确性好,但 TLB 在关键路径上
  • 虚拟地址缓存(VIVT):直接用虚拟地址查 cache,cache miss 时才查 TLB。更快,但有同义词/同名问题
  • 常见优化(VIPT):用虚拟地址的 index 位查 cache(与 TLB 并行),用物理地址的 tag 位做比对。兼顾速度和正确性

现代 x86 的 L1 cache 通常用 VIPT:TLB 查找和 cache 查找并行进行,不会增加额外延迟。

1.4 · A 回答问题#

TLB 是 MMU 中缓存”虚拟地址 → 物理地址”映射的硬件缓存,把原本需要 4 次内存访问的 page walk 压缩到 1 个周期完成。

关键理解点:

  1. TLB 解决的是 page walk 太慢的问题,不是 cache miss 的问题
  2. TLB miss 比普通 cache miss 更贵,因为 page walk 本身要多次访存
  3. TLB 条目数量极少(几十~几百),所以覆盖范围有限,大页是直接的优化手段
  4. 上下文切换是 TLB 性能的大敌,ASID/PCID 是避免全量 flush 的关键技术
  5. 现代 CPU 用 VIPT 让 TLB 查找和 L1 cache 查找并行,消除了额外延迟