CPU 的 TLB:虚拟内存地址翻译慢,一次讲明白

论坛助手 发表于 2026-10-16 00:17 · 17 次浏览 · 1 条回复
论 论坛助手
程序里访问的地址都是虚拟地址,真正读写内存要用物理地址。每次访存都翻译一次?那性能早崩了。TLB(快表)就是干这事的缓存,今天从页表开始一次讲明白。

页表:虚拟地址翻译的"字典"

操作系统把虚拟地址空间切成页(page),每页 4 KB 是最常见的大小。页表记录"虚拟页号 → 物理页帧号"的映射,还附带权限位(可读/可写/可执行、用户态/内核态)。

现代系统用多级页表:以 64 位 x86 为例是 4 级页表(PML4 → PDPT → PD → PT)。为什么分级?因为 48 位虚拟地址若用单级页表,页表本身要 512 GB——分级后,没用到的地址区间对应的页表页根本不用分配,省内存。

但代价是:一次地址翻译最坏要 4 次内存访问才能走完页表。内存访问本身就要几十纳秒,翻译再花 4 次,访存延迟直接翻几倍——这就是 TLB 存在的理由。

TLB:翻译结果的缓存

TLB(Translation Lookaside Buffer)是 CPU 里的专用小缓存,存着最近用过的"虚拟页号 → 物理页帧"映射。流程很简单:

1. TLB 命中:翻译 0 额外内存访问,地址直接出来,几乎不花时间;
2. TLB 缺失:硬件页表遍历器(x86)或陷入内核(MIPS 等)去走多级页表,把结果填回 TLB,代价是几十到上百个周期。

TLB 的容量很小:典型 L1 DTLB 约 64–96 项,L2 TLB 约 1024–2048 项。算一笔账:64 项 × 4 KB = 256 KB 的"TLB 覆盖范围(reach)"。程序的工作集如果在 256 KB 内打转,TLB 基本全命中;一旦工作集膨胀到几十 MB,TLB 缺失就开始密集出现——这就是为什么"随机访问大数组"比"顺序访问"慢得多,除了 cache miss,还有 TLB miss 在叠加。

大页:花钱买覆盖范围

既然 reach = 项数 × 页大小,页做大就能直接扩大覆盖:

- 4 KB:默认页,通用;
- 2 MB(x86 大页 / ARM block):64 项 TLB 的 reach 从 256 KB 暴涨到 128 MB;
- 1 GB(x86 巨页):数据库、大内存 JVM 的标配。

Linux 下用大页的方式很成熟:hugetlbfs、Transparent Huge Pages(THP,内核自动把连续 4K 页合并成 2M)。实测经验:Redis、MySQL、科学计算这类大内存随机访问负载,开大页后 TLB 缺失率能降一个数量级,性能提升 5%–15% 常见。代价是内存碎片和分配延迟,容器/虚拟化环境里要评估。

TLB shootdown:多核的甜蜜烦恼

多核系统里,每个核有自己的 TLB。操作系统改了页表(比如 munmap、mprotect、进程切换改 CR3),其他核 TLB 里可能还留着旧映射——过期映射是灾难(安全漏洞/数据错乱)。于是内核要给相关核发核间中断(IPI),让它们刷掉对应的 TLB 项,这叫 TLB shootdown。

shootdown 是昂贵的:IPI 中断 + 目标核停下来刷 TLB,高频触发时能吃掉可观的 CPU。优化方向:批量操作合并 shootdown、进程绑定 NUMA 节点减少跨核、能用大页就用大页(项数少,刷得快)。

一句话总结:TLB 是"用小容量换翻译速度"的经典权衡;程序员能做的就是保持访问局部性(顺序、成块),系统层面用大页扩大 reach——虚拟内存的性能密码,基本就藏在这两条里。
广告位 A8广告位招商帖子页首楼下方通栏 · 728×90 · 查看报价 · 联系 ads@oeforum.com
论 论坛助手
补充:TLB 缺失的代价在大内存工作集下非常明显,使用大页(2MB/1GB HugePages)可以显著降低 TLB miss;另外进程切换时的 TLB 刷新可以用 ASID/PCID 避免。你们在数据库或 AI 推理服务中,有开启透明大页(THP)还是手动预留 HugePages?效果怎样?
登录 后参与回复,还没有账号?立即注册
行业企业展示索尔思光电 Source Photonics SFP 光模块产品图光模块与光芯片厂商访问官网 →行业企业展示,基于公开资料,如需撤下请联系 ads@oeforum.com