存储系统

Cache 与虚拟内存综合题的固定动作:容量换位数、画地址分解链、按问法对号入座。

18 套卷子里,除 2022 和 2026 外的 16 年都有至少一道以 Cache 或虚存为主线的综合题,是整张卷子上单点收益最高的一支(见知识点优先级)。

知识框架概要

这一支的全部考点挂在两条链上。先把这两条链背成骨架,再做题——每一小问都只是骨架上的某一个节点。

一、地址翻译链:VA → PA 的实质是 VPN → PPN,页内偏移原样抄下来

  1. VA = 虚页号 VPN ‖ 页内偏移 —— 拆分点只由页大小决定,见 页面划分和地址结构
  2. VPN → TLB —— 一个装页表项的小 Cache,全相联或组相联;命中直接拿到 PPN,见 TLB
  3. VPN → 页表 —— 只在 TLB 缺失时走;多级则先页目录再页表,见 多级页表
  4. PA = 页框号 PPN ‖ 页内偏移(偏移位不变,这是 TLB 与 Cache 各种「能不能提前索引」结论的唯一根据)

二、Cache 访问链:PA → 数据,靠三段地址定位

  1. PA = 标记 Tag ‖ 组号 Index ‖ 块内地址 Offset —— 见 cache 地址结构
  2. 组号选中唯一一组 —— 直接映射是「组内一行」,n 路组相联是「组内 n 行」,全相联只有一组,见 cache 和主存映射方式
  3. 组内逐路比 Tag 并查有效位 —— 命中按 Offset 取字;缺失访主存调入整块
  4. 缺失后两件事:替换算法(LRU / FIFO / 随机)与写策略(全写 + 非写分配 / 写回 + 写分配),见 替换算法cache 写策略

两条链串起来就是一次完整访存,草稿上默画一遍,做题时只需往上填数:

虚拟地址 ─┬─ 虚页号 ─→ TLB ─命中→ 页框号
          │             └缺失→ 页表(多级先查页目录)─→ 页框号
          │                       └ 有效位 0 → 缺页异常 → 磁盘
          └─ 页内偏移 ──────────────────┐
物理地址 = 页框号 ‖ 页内偏移
          ├─ 标记 + 组号 ─→ Cache ─命中→ 送 CPU
          └─ 块内地址              └缺失→ 访主存,调入整块

完整时序见 访存过程

解题流程模板

这三步有严格先后:位数没算完就去画链、链没画完就去套公式,是这一支最主要的失分方式。

第一步:所有容量换算成位数

题干给的量直接推出关系
页大小页内偏移位数log₂(页大小)
主存块大小块内地址位数log₂(块大小)
Cache 数据区容量、路数、块大小组数、组号位数组数 = 容量 ÷ (路数 × 块大小)
物理地址位数标记位数物理地址位数 − 组号位数 − 块内地址位数
虚拟地址位数虚页号位数虚拟地址位数 − 页内偏移位数
页表基址、页表项大小页表项地址基址 + 表项号 × 表项大小

这张表填完,「占几位」「在哪一组」「页表项地址是多少」这几类小问就已经有答案了。会失分的情况通常是没填完就急着算下一问。

第二步:把链实例化

在草稿上重画那条链,把第一步算出的位数标在每一段上:虚页号几位、页内偏移几位、标记几位、组号几位。每个小问只落在这条链的一个位置上,先定位再计算,不要先套公式。

第三步:按问法对号入座

小问的问法落在链上哪一层固定动作
某虚拟地址的物理地址是多少页表页框号 × 页大小 + 页内偏移;位数对齐时直接拼接
页目录项 / 页表项的地址页表基址 + 表项号 × 表项大小,虚地址和物理地址各算一次
在 Cache 的哪一组 / 哪一行Cache取物理地址里的组号位段,不要用整个地址去除
命中率 / 缺失率Cache一块装 k 个元素,顺序遍历的命中率 = (k−1)/k
平均访问时间Cache命中时间 + 缺失率 × 缺失损失
缺页次数页表无置换时按首次访问页数算;有置换时按完整访问序列模拟
按行还是按列遍历更快Cache只比较访问步长与块大小

页表题的核心动作永远是同一组「两次乘加」:先用表项号定位页表项,再用页框号拼出物理地址。2013#462020#462024#45 是同一套题,其中 2024 年多绕一层——页表自己也放在某个页里,也要被翻译一次

两种变形

以下“虚拟地址直接索引 Cache”讨论以题目明确采用 VIPT(Virtually Indexed, Physically Tagged)模型为前提;未说明时仍应按题设给出的访问顺序判断。

用虚拟地址直接查 Cache 的条件只有一句:组号位数 + 块内地址位数 ≤ 页内偏移位数。满足时这些位在虚拟地址和物理地址中完全相同,不必等地址转换结束就能开始索引 Cache。2011#442016#452019#46 靠它推理,2025#43 直接问「VA 中哪些位可以作为 Cache 索引」。

题干给了汇编或 C 代码,是把地址藏起来的写法,固定三步:

  1. 从代码里取数组首地址和元素大小,算出目标元素的虚拟地址;
  2. 把这个虚拟地址送进上面那条链;
  3. 遇到「哪种遍历顺序更好」,只比较步长和块大小。

会用到 汇编代码数据对齐大小端

历年题索引

框架和流程是通用的,下面这张表只用来查「某一年把题绕在了链上的哪一层」,练完一年再回上面对一遍流程。

真题主线这一年特别问了什么
2009#46请求分页 + TLB + LRU依次访问三个虚地址各需多少时间
2010#44Cache 直接映射行遍历与列遍历的命中率谁更高
2010#46分页 + FIFO / CLOCK同一个虚地址在两种置换算法下的物理地址
2011#44页表 + TLB 四路组相联 + Cache用物理地址访问 Cache 时的字段划分
2012#43Cache 缺失率 + 主存带宽由每秒缺失次数反推最低主存带宽
2012#45驻留集 + 空闲页框链表该置换策略是否适合时间局部性好的程序
2013#43Cache 块大小 + 突发传送读一个主存块需几次突发传送
2013#46二级页表页目录号与页表索引的表达式
2014#45指令 Cache + 缺页 + TLB哪条指令溢出、读磁盘与查 TLB 各几次
2015#46二级页表页目录加页表一共占多少页
2016#45TLB 全相联 + Cache 二路组相联为什么 Cache 可以直写而页面用回写
2017#45二级分页 + 机器指令取第 1 条指令时访问页目录与页表的第几项
2018#44TLB + Cache 回写TLB 用 SRAM 还是 DRAM、有效位的作用
2018#45二级页表 + 改进型 CLOCK由页目录号、页号、偏移反向合成虚拟地址
2019#46分页 + 指令 Cache 四路组相联call 指令只可能在哪一组命中
2020#44Cache 八路组相联 + 直写每行的 Tag 与 LRU 各几位、有没有修改位
2020#46二级页表 + 二维数组页目录项与页表项的物理地址
2021#44TLB 二路组相联 + LRU虚地址增到 32 位后表项要增加几位
2023#43请求调页 + Cache 四路组相联缺页次数与发生缺页的页故障地址
2024#44页式管理 + 汇编a[i] 所在页号、数组至少占几页
2024#45页表项定位页表所在页的页号及其页表项
2025#43Cache 八路组相联 + 缺页哪些 VA 位可作索引、平均访问时间
2025#46进程虚拟地址空间分区PCB、ptr、字符串常量各在哪个区域

易错清单

  • 组数忘了除路数。八路组相联的组数是「容量 ÷ 路数 ÷ 块大小」,少除一次路数,后面所有位数都错。
  • 按字编址和按字节编址混用。这只决定主存单元宽度,不能由它推寄存器宽度。
  • 不检查条件就用虚拟地址索引 Cache。见上面那一句不等式。
  • 把“首次装入”当成所有缺页题的规则。无置换时缺页次数才等于首次访问页数;出现 FIFO、LRU、CLOCK 或明确的置换后,必须逐次模拟,缺页次数可能超过数据占用页数。
  • 漏掉 TLB / Cache 初始为空造成的强制缺失
  • 二级页表只做了一次乘加。定位页表项和拼物理地址是两步,不能合并。

上一页:数的表示与运算;下一页:CPU 与指令系统