精简版 · 小杯2026-08 冻结,已停止更新(发布前修订了 4 处已知错误)。后续勘误与新增内容只在正式版。看正式版(中杯)→
Skip to content

虚拟存储器(硬件视角)

考情分析

虚存的硬件机制在组成原理和操作系统中都有考查,408 大题常以虚实地址转换结合 Cache 的形式出现,是跨章节综合题的重点。

大纲定位

考纲第三章(七)「虚拟存储器」四条:

  1. 虚拟存储器的基本概念
  2. 页式虚拟存储器 —— 注明「基本原理,页表,地址转换,TLB(快表)」
  3. 段式虚拟存储器的基本原理
  4. 段页式虚拟存储器的基本原理

注意深度差:第 2 条大纲给了四个子项,第 3、4 条只有「基本原理」四个字、没有任何子项。所以页式要学到能算,段式/段页式知道结构和翻译步骤即可。

术语先对齐

真题卷面用的是实页号(也叫页框号),不是「物理帧号」。本文两种说法都给,做题时按题面走:

本文写法真题常见写法含义
虚页号 VPN虚页号虚拟地址的高位段
实页号 PFN实页号 / 页框号物理地址的高位段
页内偏移 offset页内地址低位段,翻译前后不变

虚拟地址与物理地址

程序使用虚拟地址(逻辑地址),硬件将其翻译为物理地址后才能访问主存。

虚拟地址结构(分页机制):

[虚页号(VPN)  页内偏移(offset)]

页大小 =2,如 4 KB 页 → offset 12 位。

卷面要写位区间。给分点常要求答成 [:] 的形式,只答位数会丢分。32 位虚地址、4 KB 页时:

offset=VA[11:0],VPN=VA[31:12]

编者注(易错):翻译只换高位段,offset 位数与取值都不变。所以物理地址位数 = 实页号位数 + offset 位数,实页号位数由物理地址位数决定,与虚地址位数无关——两者可以不等。

页表

页表存储在主存中,由操作系统管理。每个进程有一张页表。

图 7.40 主存中的页表示例

图 7.40 主存中的页表示例

图中页表项含装入位、修改位、使用位、访问权限位、禁止缓存位、存放位置。装入位 = 0 的虚页(VP0、VP3、VP4、VP6)在磁盘上,= 1 的(VP1、VP2、VP5、VP7)才在主存里。

页表项(PTE)主要字段:

字段别名说明
实页号物理帧号 PFN、页框号对应的主存页框
有效位装入位、Present该页是否在主存中
脏位修改位、Dirty该页是否被修改(换出时决定要不要写回磁盘)
访问位使用位、Referenced最近是否被访问(用于页面替换)
保护位访问权限位读/写/执行权限

翻译过程

图 7.42 分页式虚存的地址转换

图 7.42 分页式虚存的地址转换

图中四步:① 页表基址寄存器给出页表首址 → ② 虚页号作下标定位到页表项 → ③ 取出实页号 → ④ 与页内地址拼接成物理地址。

物理地址=实页号  offset

这里的 位串拼接,不是算术加。等价的算术写法是 实页号×页大小+offset——因为 offset 位数正好等于页大小的位数,拼接和"乘以页大小再加"结果相同。

谁来检查这些控制位

这一问真题直接考过。地址翻译由 MMU(Memory Management Unit,存储管理部件,含 TLB)完成:

检查项由谁检查违反后果
有效位 = 0MMU触发缺页异常,转 OS 处理
保护位不符MMU触发访问越权异常
Cache 是否命中Cache 控制器在 MMU 交出物理地址之后才登场

顺序是固定的:MMU 先把虚地址翻成物理地址(这期间可能触发 TLB 缺失、缺页、越权),拿到物理地址后 Cache 才开始查。

缺页之后会发生什么

缺页是异常(exception),不是中断——它是同步的,与当前这条指令绑定,习惯上也被称作「缺页中断」,但判断题里要按异常算。

关键的一条:缺页处理完毕后,返回点是引发缺页的那条指令本身,该指令被重新执行一遍。

这条不只是概念题。它有可计数的后果:同一次访存因为重做,TLB 会被查两次——统计访问次数的大题里漏掉这一次就会差 1。

编者注(易错):别把「缺页由 OS 处理」当成「这是操作系统的考点、组成原理不考」。缺页的触发机制、返回点、重新执行带来的计数变化都在组成原理卷面上出现过。

多级页表

32 位地址空间,4 KB 页,单级页表需要 220 个页表项,占 4 MB 内存(每个进程)。

两级页表:把 VPN 再切成两段——高段作页目录索引,低段作页表索引

[页目录索引L1  页表索引L2  页内偏移offset]

翻译要走两跳:页目录基址寄存器 → 页目录项(给出该页表的基址)→ 页表项(给出实页号)。所以TLB 缺失时,两级页表要访问 2 次主存才拿到实页号,再加 1 次取数据。

64 位系统通常用 4 级页表(x86-64 的四级依次是页全局目录、页上级目录、页中间目录、页表,常写作 PML4 / PDPT / PD / PT)。

TLB(快表)

问题:每次地址翻译都要访问主存中的页表,一次访存变成"一次翻译 + 一次取数",效率低下。

TLB(Translation Lookaside Buffer,快表/地址翻译缓存):页表的 Cache,存放最近使用的页表项,容量小(64~1024 项),速度极快(SRAM)。

TLB 的映射方式:全相联组相联

TLB 项数少,常采用全相联,查找时并行比较所有项的标记。但组相联的 TLB 也考过,别把"TLB 一定是全相联"当结论。

组相联 TLB 的字段切法与 Cache 完全同构,只是被切的对象是虚页号而不是整个地址:

VPN=[TLB 标记  TLB 组号log2(TLB 组数) ]

其中 TLB 组数 = TLB 项数 ÷ 路数。

编者注(易错):TLB 组号取的是虚页号的低位,不是虚拟地址的低位。虚拟地址的低位是页内偏移,与 TLB 无关。

举例:虚地址 30 位、页大小 4 KB、TLB 共 16 项 2 路组相联。

  • offset = VA[11:0],VPN = VA[29:12](18 位)
  • TLB 组数 =16÷2=8 → TLB 组号 3 位 = VA[14:12]
  • TLB 标记 =183=15= VA[29:15]

TLB 表项里有什么

和页表项不完全一样——TLB 是"带标记的页表项副本":

字段宽度由谁决定
TLB 标记虚地址位数(VPN 位数减去组号位数)
实页号物理地址位数
有效位 / 脏位 / 替换算法位与地址位数无关

所以真题问"虚地址加宽 2 位,TLB 每项增加几位"时,答案是只有标记 +2 位,实页号和控制位都不变。

TLB 也要替换

TLB 装满后再来新项就要替换,常用 LRU。命中时也要更新最近使用顺序——这一点漏掉,后面该换谁就会判错。

地址翻译流程(含 TLB)

虚拟地址

查 TLB(极快)

TLB 命中?
 是(TLB Hit)→ 直接得到物理地址
 否(TLB Miss)→ 查主存页表

                装入位 = 1?
                 是 → 得到物理地址 → 更新 TLB
                 否 → 缺页异常 → OS 调页 → 重新执行本指令

用物理地址访问数据

查 Cache

Cache 命中?
 是 → 从 Cache 返回数据
 否 → 访问主存,装入 Cache

完整的 TLB + 页表 + Cache 联合访问

图 7.43 TLB 和 cache 的访问过程

图 7.43 TLB 和 cache 的访问过程

这张图把三级画全了:上半部主存中的页目录与页表,中间 TLB(虚页号切成标记 + 组索引,两路并行比较后经 MUX 输出实页号),下半部 Cache(物理地址切成标记 + 组索引 + 块内地址)。注意页内地址那 12 位从头到尾没进 TLB,直接旁路到物理地址的低位。

八种组合,三种不可能

只列 TLB × Cache 两维是不够的,页表命中与否是独立的第三维

TLBPage(页表)Cache可能?说明
HitHitHit最快
HitHitMiss访存取数据
HitMissHitTLB 项是页表项的副本,命中即说明页在主存
HitMissMiss同上
MissHitHit查页表得地址,数据恰在 Cache
MissHitMiss查页表 + 访存
MissMissHit页都不在主存,其内容不可能在 Cache
MissMissMiss缺页,最慢

两条判据记住就够:

  • TLB 命中 ⇒ 页必在主存(所以 TLB hit + Page miss 不可能)。反过来,OS 把某页换出时必须同步让对应的 TLB 项失效,否则这条判据就被破坏了。
  • 页不在主存 ⇒ Cache 不可能命中(Cache 缓存的是主存内容)。

交互可视化

加载可视化中...

段式虚拟存储器

页式是把地址空间等分成固定大小的页;段式是按程序的逻辑结构分成长度不等的段(代码段、数据段、栈段……)。

虚拟地址是二维的:

[段号  段内地址]图 7.45 分段式虚存的地址转换

图 7.45 分段式虚存的地址转换

翻译过程:段表基址寄存器 → 加上段号定位到段表项 → 取出段首址,与段内地址相加得到物理地址。

段表项的关键字段:

字段作用
段首址(段基址)该段在主存中的起始地址
段长该段的长度
装入位该段是否已调入主存

段长是段式相对页式在硬件上的唯一实质增量:因为段是变长的,必须检查「段内地址 < 段长」,越界则触发异常。页式不需要这个检查——页内偏移的位数天然就限死了范围。

还有一处和页式不同:物理地址是段首址 + 段内地址(算术加),而不是拼接——段首址不必对齐到 2 的幂边界。

段页式虚拟存储器

先分段、段内再分页,虚拟地址是三段

[段号  段内页号  页内偏移]

翻译要走两张表:

  1. 段号查段表,取出的是该段页表的基址(注意:不是段基址)
  2. 段内页号查该段的页表,取出实页号
  3. 实页号与页内偏移拼接成物理地址

所以无 TLB 时,一次访存要 3 次主存访问:查段表 1 次 + 查页表 1 次 + 取数据 1 次。

编者注(易错):段页式常见的干扰项是"只需一次访存"。段表项存的是页表基址而不是最终地址,两级表必须都查。

三者对比

页式段式段页式
划分依据等长,硬件定变长,程序逻辑定先段后页
虚地址切几段223
表项关键字段实页号段首址 + 段长段表存页表基址;页表存实页号
地址合成拼接相加(需越界检查)拼接
无 TLB 时访存次数223
对程序员透明(页号不可见)不透明(段号是程序结构的一部分)段不透明、页透明
碎片内碎片外碎片内碎片

段的共享与保护策略、外碎片紧凑、页置换算法属于操作系统部分的内容,这里不展开。

地址翻译计算例题

:32 位虚拟地址,页大小 4 KB,物理地址 24 位。虚拟地址 0x00082840,页表内容如下(装入位 = 1 才有效):

虚页号(十进制)装入位实页号
12810x00A
1290——
13010x018
13110x0C3

Step 1. 定各字段位数与位区间。 页大小 4 KB offset =log24096=12 位。

  • offset = VA[11:0]
  • VPN =3212=20= VA[31:12]
  • 实页号 =2412=12

Step 2. 切出字段的值。

0x00082840offset=0x840,VPN=0x00082

Step 3. 把 VPN 换成十进制再查表。

VPN=0x82=8×16+2=130

查页表第 130 项(不是第 82 项),装入位 = 1,实页号 = 0x018

编者注(易错):页表的虚页号列通常按十进制编号,而地址是十六进制。必须先换算再查表——直接拿 0x82 当行号去查是这类题最常见的失分点。

Step 4. 拼接成物理地址。

PA=0x01812 位实页号  0x84012 位 offset=0x018840

算术验算:0x018=2424×4096+0x840=98304+2112=100416=0x18840

解题动作清单

地址翻译题的固定起手式,五步走:

  1. 由页大小定 offset 位数:offset =log2(页大小),写成 [offset位数1:0]
  2. 由虚/物理地址位数分别定 VPN 和实页号位数——两者不必相等,各减各的 offset
  3. 写出位区间,别只写位数
  4. 若考 TLB:把 VPN(不是虚地址)再切成 TLB 标记 + TLB 组号,组号位数 =log2(项数 ÷ 路数)
  5. 若接 Cache:把物理地址切成 tag + index + 块内偏移

若题目问访存次数,再叠一层:查表次数(一级页表 1、两级 2、段页式 2)+ 取数 1,缺页还要算上重新执行带来的重复查表。

考点清单

  • 虚拟地址 = VPN offset,物理地址 = 实页号 offset,offset 位数与取值都不变
  • 实页号位数由物理地址位数定,与虚地址位数无关,两者可不等
  • TLB 是页表的 Cache,常用全相联,但组相联也考过;组号取虚页号的低位
  • TLB 表项 = 标记 + 实页号 + 控制位;虚地址加宽只影响标记宽度
  • TLB 命中 页必在主存;页不在主存 Cache 不可能命中
  • 缺页是同步异常,处理完重新执行原指令(该次访存会查两遍 TLB)
  • MMU 查有效位和保护位,Cache 控制器在物理地址产生后才登场
  • 段式:段表项 = 段首址 + 段长,物理地址靠相加并需越界检查
  • 段页式:三段切分,段表存页表基址,无 TLB 时访存 3
  • 页表虚页号列是十进制、地址是十六进制,查表前先换算

教材出处

  • 袁春风《计算机组成与系统结构(第 3 版)》§7.6 虚拟存储器:图 7.40(p256)、图 7.42(p259)、图 7.43(p260)、图 7.45(p263)

真题练习