TLB 是性能瓶颈
TLB 缺失代价极高(约 100 倍指令时间),大页能指数级提升覆盖范围。
6.1810 / 6.1810 · 第 9 课 · rtm
现代操作系统如何自动在 4KB 基础页与 MB 级超级页之间做出选择?本节课以 Navarro 等人(OSDI 2002)的经典论文为核心,探讨内核对透明大页(Transparent Superpages)的支持。
上节课的重要结论:现代操作系统中,页分配通常是惰性的——远比 xv6 更加惰性:
sbrk() 申请内存时,页表一般不会立即改变好处是透明的快速启动:程序可以放心申请大量内存,而无需担心物理 RAM 的大小。
分页(Paging)也称"换页到磁盘"(Paging to Disk),其历史可以追溯到内存非常昂贵的年代。即便在今天,Linux 仍然支持换页到磁盘,原因包括:
假设一台机器只有 2 页物理内存,但程序想使用 4 页数据:
| 组件 | 内容 |
|---|---|
| 页表 | 4 个 PTE |
| 物理 RAM | 2 页(初始空闲) |
| 磁盘 | 4 页交换空间 + 1 页可执行文件 |
处理流程:
我们实际上把 RAM 当作磁盘的缓存,磁盘充当"后备存储"。
如果驱逐的页面很快就会被使用,将引发又一次缺页和磁盘读取。一次磁盘读取约需 1 毫秒——相当于一百万条指令的时间!糟糕的驱逐策略会导致大量耗时的缺页异常。
内核维护一个包含所有物理页号的 LRU 列表:
三个 LRU 列表:
| 列表 | 作用 |
|---|---|
| Active | 最近被访问过的页面 |
| Inactive | 从 Active 降级、尚未写回的页面 |
| Cache | 已清除脏位、长时间未使用的干净页面 |
Cache 列表中的页面可直接用于缺页分配,保持 Cache 列表非空对快速处理缺页至关重要。
干净页在磁盘上已有副本(来自之前的换出或只读可执行文件),重用前无需写回磁盘;脏页则必须先写回。驱逐干净页可显著降低缺页延迟。
LRU 本质上是一种预测:最近使用的页面很可能很快再次使用。多数情况下效果很好,但某些场景下表现极差:
反例:对巨大内存空间的重复顺序扫描——程序几乎会在每个页面上缺页,而 LRU 恰好会驱逐程序即将访问的页面!因此,某些系统采用随机替换策略。
Translation Lookaside Buffer (TLB) 是 CPU 内部的虚拟地址到物理地址转换的缓存,本质上是一张 (va, pa) 表。
每次内存引用(加载、存储、指令取指)都需要 va→pa 转换。CPU 需要大约每周期完成一次(纳秒级)。
由于必须极快,TLB 通常只有很少的条目:
128 条目 × 4KB 页 = 半兆字节!
1024 条目 × 4KB 页 = 4 兆字节
对于拥有 16GB+ RAM 的机器和程序来说微不足道。任何常规使用超过此范围的程序都会 TLB 缺失。
128 个 TLB 条目 × 2MB 页 = 1/4 GB!现代 CPU 确实拥有至少这么大的超级页。
如果程序只使用每个大页的一小部分,会浪费大量 RAM。因此,能够混合使用小页和大页是有吸引力的。
目标:内核自动在基础页和超级页之间选择,以提升 TLB 覆盖范围、减少 TLB 缺失的浪费时间。需要适应程序特征(包括行为变化)、兼顾大小程序、应对松紧内存压力,并透明地完成。
给进程分配 2MB 超级页本质上是一种预测:进程将在不久的将来较密集地使用这 2MB 空间。预测错误 → 浪费 RAM。核心张力:更少 TLB 缺失 vs. 浪费 RAM。
| 策略 | 优点 | 缺点 |
|---|---|---|
sbrk() 调用时 |
— | 难以从参数猜测情况;sbrk(2MB) 不一定意味着会全部使用 |
| 2MB 区域内首次缺页时 | 知道它至少会用一些 RAM;立即获益 | 可能只用一小部分,浪费 RAM;假设超级页通常合适 |
| 区域内所有页都缺页时(论文方案) | 确定使用了 100% 的 2MB | 在超级页生效前让程序运行了相当长时间 |
必须满足:连续、2MB 对齐、空闲。物理内存通常是"碎片化"的——已用和空闲页交错排列。
如果程序只使用 2MB 的一部分,预留页仍可作为缓存页被原始映射重用,避免了内存浪费。只有当程序确实使用整个 2MB 时,才提升为超级页。
内存紧张时,小页可能占用更少 RAM。但:
方案:对超级页设置读保护,首次写入时降级,以获得更细粒度的 Dirty 位。
论文 Table 1 显示,在各种真实基准测试中,超级页通常带来约 10% 的性能提升,有时更高。但请注意,该表的前提是"内存充足"。
收益往往相当适中,但代价(内存浪费)可能非常大。这正是透明大页设计持续演进的根源。
Q1:TLB 的"覆盖范围"(reach)是什么?
Q2:为什么使用大页(超级页)?
Q3:论文的超级页分配方案中,"预留"页面但不立即分配的好处是什么?
Q4:为什么 LRU 页面置换策略对"重复顺序扫描巨大内存"的程序表现很差?
Q5:为什么内核有时需要降级(demote)超级页?
TLB 缺失代价极高(约 100 倍指令时间),大页能指数级提升覆盖范围。
分配超级页是对程序行为的预测——预测错误会浪费 RAM,预测正确减少 TLB 缺失。
物理内存碎片化使连续 2MB 空闲区域难以找到,需要预留或压缩策略。
透明大页设计持续变化,收益适中但代价可能很大,许多应用选择显式管理。