页式虚拟存储器

页式是三种虚拟存储器里唯一在统考中出计算题的一种,因为它的地址结构最规整:页大小是 2 的幂,于是虚拟地址天然分成”虚页号 + 页内偏移”两段,页内偏移原样照抄到物理地址,只有页号需要翻译。

这一节的三个层次要分清:页表是翻译的数据结构(放在主存里)、TLB 是页表的 Cache(放在 MMU 里)、MMU 是完成整个翻译的硬件部件。它们不是三个并列的东西,而是一层套一层。

机制

页、页框与地址结构

虚拟空间划分成等长的页(Page),主存划分成同样大小的页框(Page Frame,也叫实页、页帧)。

虚页号需要翻译页内偏移原样照抄物理页号翻译结果页内偏移不变

页内偏移位数 页大小,虚拟地址与物理地址的这一段完全相同。 因此:

  • 虚页号位数 = 虚拟地址位数 页大小
  • 物理页号位数 = 物理地址位数 页大小
  • 两者通常不等(虚拟空间可以大于物理空间)

页表与页表项

页表是”虚页号 → 物理页号”的映射表,本身存放在主存中,每个进程一张。页表基址寄存器(页表寄存器)保存当前进程页表的起始物理地址,进程切换时随之切换。页表项地址页表基址虚页号页表项大小页表项的字段:

字段作用
物理页号翻译结果
有效位 / 装入位该页是否在主存中——为 0 则缺页
脏位 / 修改位该页是否被写过,决定换出时要不要写回辅存
访问位 / 引用位供替换算法使用(CLOCK 的依据)
访问权限位读/写/执行权限,越权则产生保护异常

页表项里没有虚页号——虚页号是页表的下标,不需要存。这与 TLB 项形成对照:TLB 是相联查找的,必须存虚页号做标记。

TLB:页表的 Cache

每次访存都要先查页表,而页表在主存里,这意味着每次访存要变成两次。 TLB(Translation Lookaside Buffer,快表)就是为消掉这一次而设的:把最近用过的页表项缓存在 MMU 内部。

  • TLB 行数很少(几十到几百),因此通常采用全相联或高路数组相联,用相联存储器一拍出结果
  • TLB 项 = 标记(虚页号)+ 页表项内容——比页表项多一个标记字段
  • 进程切换时 TLB 必须失效(或用进程标识 ASID 区分),否则会用错映射

“快表”和”慢表”的说法:TLB 是快表,主存中的页表是慢表。两者内容是包含关系,不是并列关系——TLB 里的每一项在页表里都有。

疑问点:MMU 是什么,它和页表、TLB 是什么关系

MMU(Memory Management Unit,存储管理部件)是 CPU 内部专门负责地址转换的硬件模块。 三者是一层套一层的关系,不是并列的:

是什么在哪
页表虚页号→物理页号的数据结构主存中(每进程一张)
TLB页表项的高速缓存MMU 内部
MMU完成整个转换的硬件部件CPU 内部

MMU 内部包含:TLB、页表基址寄存器、页表遍历逻辑(TLB 未命中时自动去主存查页表)、权限检查电路。

MMU 做什么、不做什么,是与操作系统的分界线: MMU 做:查 TLB → 未命中则遍历页表 → 检查有效位和权限 → 拼出物理地址。全部由硬件在一次访存内完成,不需要任何软件参与。 MMU 不做:决定把哪一页调进来、淘汰哪一页、去辅存的什么位置取。它只在有效位为 0 或权限不符时产生一个异常(缺页故障 / 保护故障),把控制权交给操作系统,剩下的全是软件的事。

这条分界正是”硬件管翻译、软件管替换”的物理体现(见 3.6.1)。 一个佐证:计算机上电引导的最初阶段 MMU 是关闭的,CPU 直接使用物理地址;等操作系统建好页表后才打开 MMU。在此之前虚拟地址这个概念根本不存在。 操作系统一侧的完整视角见 OS 3.2.2 请求分页管理方式。

TLB、页表与 Cache 的访问次序

flowchart TD
    VA["虚拟地址:虚页号 | 页内偏移"] --> T{"查 TLB"}
    T -->|"命中"| PA["拼出物理地址"]
    T -->|"未命中"| PT{"查主存中的页表<br/>(MMU 自动完成)"}
    PT -->|"有效位=1"| L["装入 TLB"] --> PA
    PT -->|"有效位=0"| PF["缺页异常 → 操作系统调页"]
    PA --> C{"查 Cache"}
    C -->|"命中"| HIT["取数完成"]
    C -->|"未命中"| M["访问主存,装入 Cache"] --> HIT

    classDef os fill:#fadbd8,stroke:#c0392b
    classDef fast fill:#d5f5e3,stroke:#27ae60
    class PF os
    class T,C fast

三处判断合起来有 8 种组合,其中 3 种在物理上不可能:

TLB页表Cache可能吗理由
命中命中命中✅最快的情形
命中命中未命中✅要访问主存取数
命中未命中命中/未命中❌(两种)TLB 命中说明该页一定在主存,页表不可能未命中
未命中命中命中✅页表项没缓存,但数据缓存了
未命中命中未命中✅两次访存
未命中未命中命中❌页不在主存,它的内容不可能出现在 Cache 里
未命中未命中未命中✅缺页,最慢

两条”不可能”的理由要能说出来,这是简答题的固定问法: TLB 是页表的子集 → TLB 命中蕴含页表命中; Cache 缓存的是主存内容 → 页不在主存则其内容必不在 Cache。

有效访问时间

这类题的口径比公式重要。 设 TLB 访问时间 、主存访问时间 、TLB 命中率 ,忽略缺页:

串行查找(先查 TLB,未命中再查页表):并行查找(TLB 与页表同时启动):若还要计入缺页率 ,再加一项 缺页处理时间;缺页处理时间是毫秒级,一旦出现就会主导整个结果。

多级页表时,未命中的那一路要访存的次数等于页表级数加一。 两级页表 TLB 未命中要访存 3 次(两级页表各一次 + 取数一次)。

边界

页内偏移在虚拟地址和物理地址中完全相同。 这一条是所有页式计算题的第一步,也是”页大小改变时哪些位数会变”这类问题的判据。

页表存放在主存中,TLB 在 MMU 内。 说”TLB 在主存中”或”页表在 CPU 中”都是错的。

TLB 项比页表项多一个标记字段(虚页号)。 因为 TLB 是相联查找,页表是按下标索引。

页表基址寄存器随进程切换。 这是进程的地址空间彼此隔离的硬件基础,见 OS 2.2.4 进程切换。

“TLB 未命中”和”缺页”是两回事。 TLB 未命中只是要多访存一次页表,由硬件自动完成,不产生异常;缺页才产生异常并交给操作系统。把两者混为一谈是本节最常见的错误。

页大小的权衡:页大到一定程度页表变小、缺页率下降,但页内碎片增大、一次调页的时间变长。与 Cache 块大小是同一种取舍。

计组只到”缺页异常产生”为止。 调页算法、页框分配、抖动与工作集全部在 OS 3.2。

对照速查

结构位置是否含虚页号查找方式
页表主存否(虚页号是下标)按下标索引
TLBMMU 内部是(作标记)相联比较
CacheCPU 内/旁是(作标记)按映射方式
事件谁处理是否产生异常
TLB 未命中MMU 硬件否
Cache 未命中硬件否
缺页(有效位=0)操作系统是(故障)
越权访问操作系统是(保护故障)

考点

  • 页内偏移在虚实地址中相同,只有页号需要翻译
  • 页表在主存、TLB 在 MMU、MMU 在 CPU,三者层层包含
  • 页表项无虚页号,TLB 项有虚页号做标记
  • 页表项含:物理页号、有效位、脏位、访问位、权限位
  • MMU 只做翻译和检查,不做替换决策;异常一产生就交给操作系统
  • 8 种命中组合中 3 种不可能,理由是 TLB ⊂ 页表、Cache 缓存主存内容
  • TLB 未命中不产生异常,缺页才产生异常
  • EAT 的串行/并行口径必须写明
  • 页表基址寄存器随进程切换

链接