页式虚拟存储器
页式是三种虚拟存储器里唯一在统考中出计算题的一种,因为它的地址结构最规整:页大小是 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 未命中要访存 3 次(两级页表各一次 + 取数一次)。
边界
页内偏移在虚拟地址和物理地址中完全相同。 这一条是所有页式计算题的第一步,也是”页大小改变时哪些位数会变”这类问题的判据。
页表存放在主存中,TLB 在 MMU 内。 说”TLB 在主存中”或”页表在 CPU 中”都是错的。
TLB 项比页表项多一个标记字段(虚页号)。 因为 TLB 是相联查找,页表是按下标索引。
页表基址寄存器随进程切换。 这是进程的地址空间彼此隔离的硬件基础,见 OS 2.2.4 进程切换。
“TLB 未命中”和”缺页”是两回事。 TLB 未命中只是要多访存一次页表,由硬件自动完成,不产生异常;缺页才产生异常并交给操作系统。把两者混为一谈是本节最常见的错误。
页大小的权衡:页大到一定程度页表变小、缺页率下降,但页内碎片增大、一次调页的时间变长。与 Cache 块大小是同一种取舍。
计组只到”缺页异常产生”为止。 调页算法、页框分配、抖动与工作集全部在 OS 3.2。
对照速查
| 结构 | 位置 | 是否含虚页号 | 查找方式 |
|---|---|---|---|
| 页表 | 主存 | 否(虚页号是下标) | 按下标索引 |
| TLB | MMU 内部 | 是(作标记) | 相联比较 |
| Cache | CPU 内/旁 | 是(作标记) | 按映射方式 |
| 事件 | 谁处理 | 是否产生异常 |
|---|---|---|
| TLB 未命中 | MMU 硬件 | 否 |
| Cache 未命中 | 硬件 | 否 |
| 缺页(有效位=0) | 操作系统 | 是(故障) |
| 越权访问 | 操作系统 | 是(保护故障) |
考点
- 页内偏移在虚实地址中相同,只有页号需要翻译
- 页表在主存、TLB 在 MMU、MMU 在 CPU,三者层层包含
- 页表项无虚页号,TLB 项有虚页号做标记
- 页表项含:物理页号、有效位、脏位、访问位、权限位
- MMU 只做翻译和检查,不做替换决策;异常一产生就交给操作系统
- 8 种命中组合中 3 种不可能,理由是 TLB ⊂ 页表、Cache 缓存主存内容
- TLB 未命中不产生异常,缺页才产生异常
- EAT 的串行/并行口径必须写明
- 页表基址寄存器随进程切换
链接
- 🏠 返回总览:计算机组成原理第 3 章:存储系统总览
- ⬅️ 上一节:3.6.1 虚拟存储器的基本概念
- ➡️ 下一节:3.6.3 段式虚拟存储器
- 🔗 3.5.3 相联存储器(TLB 的实现基础)
- 🌐 跨科:OS 3.1.3 基本分页存储管理、OS 3.2.2 请求分页管理方式
- 📖 名词库:第 3 章名词库