TLB — 转换检测缓冲区(快表)
一句话
TLB(Translation Lookaside Buffer)是 CPU 内部的一个硬件缓存,用于加速虚拟地址到物理地址的转换,是理解进程/线程切换开销差异的关键。
为什么需要 TLB?
现代操作系统使用虚拟内存,程序访问的是虚拟地址,CPU 需要将其转换为物理地址才能访问内存。
虚拟地址 ──→ [MMU + 页表] ──→ 物理地址 ──→ 内存
页表(Page Table)存储在主内存中,每次地址转换都需要查内存 —— 这很慢(几十到几百纳秒)。而 TLB 作为 CPU 芯片上的硬件缓存,将最近使用的页表项缓存起来,查询只需约 1 个 CPU 周期(亚纳秒级)。
TLB 的原理类似 Redis
页表 = 磁盘上的数据库(慢) TLB = Redis 缓存(快) 首次访问 miss → 查页表加载到 TLB → 后续访问 hit 直接命中
TLB 的工作方式
CPU 访问虚拟地址 VA
↓
TLB 中是否有 VA 对应的映射?
├── ✅ TLB Hit(命中) → 直接得到物理地址 → 访问内存
└── ❌ TLB Miss(未命中) → 查页表(内存)→ 加载到 TLB → 访问内存
TLB Miss 的代价
TLB Miss 后需要遍历页表(多级页表需多次内存访问),代价是 10~100 倍于 TLB Hit。频繁的 TLB Miss 会显著降低程序性能。
TLB 与上下文切换
这是理解 进程切换慢、线程切换快 的核心原因:
进程切换 → 必须刷新 TLB
进程 A 运行中:TLB 中缓存了进程 A 的地址映射
↓
切换到进程 B(地址空间完全不同)
↓
TLB 中的进程 A 映射对进程 B 无效
↓
必须刷新(Flush)/ 使所有 TLB 项失效
↓
进程 B 开始运行 → TLB 为空 → 大量 TLB Miss → 性能下降- 开销:TLB 刷新 + 重新填充(称为 TLB 抖动 / TLB Thrashing)
- 缓解:现代 CPU 引入 Tagged TLB(ASID / PCID 技术),为不同进程打标签,切换时不清空 TLB
线程切换 → 无需刷新 TLB
同一进程的线程 A → 线程 B
↓
地址空间完全相同
↓
TLB 中的映射依然有效
↓
无需刷新 TLB,切换代价远小于进程切换为什么线程切换比进程切换快?
核心原因之一就是:线程切换无需刷新 TLB。进程切换不仅要切换页表、刷新 TLB,还要刷 CPU 缓存,开销远大于线程切换。
相关概念
| 概念 | 关系 |
|---|---|
| MMU(内存管理单元) | CPU 中负责地址转换的硬件单元,TLB 是 MMU 的一部分 |
| 页表(Page Table) | 存储虚拟→物理映射的数据结构,存储在内存中 |
| ASID / PCID | 为 TLB 项标记进程 ID,避免进程切换时清空 TLB |
| 大页(Huge Pages) | 使用更大的内存页(2MB/1GB)减少页表项数量,降低 TLB Miss |
大页的优化原理
传统 4KB 页:1GB 内存需要 262144 个页表项 → TLB 覆盖范围小
2MB 大页: 1GB 内存需要 512 个页表项 → TLB 覆盖范围大 → Miss 更少这就是为什么数据库(如 MySQL)和 Java JVM 常启用大页 —— 减少 TLB Miss,提升内存访问性能。
相关笔记
- 进程线程协程 — 进程上下文切换刷新 TLB 是切换慢的重要原因
- Linux-Inode详解 — 文件系统的元数据缓存(类似 TLB 的内存缓存思想)