C++ / a working model

123 / 163   ·   C11   ·   约 8 分钟

分页:更快的转换(TLB)

先记住这句话

没有硬件转换缓存,分页会太慢。TLB利用局部性,使大多数地址转换在几个周期内完成,而不是需要内存访问。

本篇内容
  1. 为何地址转换必须快速
  2. TLB:专用的转换缓存
  3. 空间局部性将顺序访问转化为命中
  4. 运行示例
  5. 动手练习

官方章节 PDF

为何地址转换必须快速

将地址空间划分为许多小页面意味着映射表变得庞大并驻留在内存中。每次加载、存储或指令获取都需要额外的内存往返来发现物理位置。这种额外延迟将主导执行时间,使分页对实际程序无法使用。

TLB:专用的转换缓存

因此,现代处理器在MMU中嵌入了一个微小的、极快的近期转换缓存。当虚拟地址到达时,硬件首先探测这个TLB。命中立即提供物理帧。未命中则遍历页表,安装新映射,并重新启动内存操作。因为TLB位于芯片上,命中仅需几个周期。

空间局部性将顺序访问转化为命中

程序经常流式访问数组或执行循环,其指令占据连续页面。一旦对某页的第一次引用填充了TLB,同一页上的附近地址就会命中而无需进一步表遍历。即使是冷TLB,也会因为数据和代码打包在一起而产生可观的命中率。

常见误区

  • 在上下文切换时忘记刷新或标记TLB条目
  • 忽略保护位检查导致安全漏洞
  • 低估大工作集导致的TLB抖动

运行一个例子

最低标准 C11 · 完整程序 · 下载 .c

#include <stdio.h>

int main(void) {
    const int page_size = 16;
    const int start_va = 100;
    const int n = 10;
    const int elem_size = 4;

    int hits = 0;
    int misses = 0;
    int prev_vpn = -1;

    printf("Simulating sequential array accesses with page size %d\n", page_size);
    printf("Array of %d ints starting at VA %d\n\n", n, start_va);

    for (int i = 0; i < n; i++) {
        int va = start_va + i * elem_size;
        int vpn = va / page_size;
        int is_hit = (vpn == prev_vpn);
        if (is_hit) {
            hits++;
        } else {
            misses++;
        }
        printf("a[%d] VA=%d VPN=%d %s\n", i, va, vpn, is_hit ? "HIT" : "MISS");
        prev_vpn = vpn;
    }

    printf("\nHits: %d  Misses: %d  Hit rate: %.0f%%\n", hits, misses, 100.0 * hits / n);
    return 0;
}

在本地编译

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-19-tlb.c -o example && ./example

预期结果

Simulating sequential array accesses with page size 16
Array of 10 ints starting at VA 100

a[0] VA=100 VPN=6 MISS
a[1] VA=104 VPN=6 HIT
a[2] VA=108 VPN=6 HIT
a[3] VA=112 VPN=7 MISS
a[4] VA=116 VPN=7 HIT
a[5] VA=120 VPN=7 HIT
a[6] VA=124 VPN=7 HIT
a[7] VA=128 VPN=8 MISS
a[8] VA=132 VPN=8 HIT
a[9] VA=136 VPN=8 HIT

Hits: 7  Misses: 3  Hit rate: 70%

CHECK YOUR UNDERSTANDING

合上答案,试着解释。

对于从虚拟地址100开始的10个4字节整数数组,页面大小16字节,仅考虑数组访问时,TLB命中率是多少?为什么即使是第一次遍历也不是0%?

查看参考答案

70%。三次未命中(每个新页一次),七次命中。空间局部性使同一页上的后续元素直接命中已缓存的转换。

继续查证

标准草案与官方章节会更新;版本标记只说明示例最低要求。

回到目录