考研学习
知识点讲义计算机组成原理

第 3 章 存储系统

408 计算机组成原理第 3 章 存储系统复习讲义,涵盖核心概念、重点考点与典型题型。

Last updated on

先建立整章的核心逻辑:

CPU 很快,但又快又大又便宜的存储器不存在。

所以计算机采用存储层次:

寄存器 → Cache → 主存 → SSD/磁盘

Cache 主要解决速度矛盾;虚拟存储器主要解决容量矛盾;二者能够成立的共同基础都是程序访问的局部性。

一、第 3 章考点地图

内容考研重要度主要题型
存储器分类、层次结构★★★概念选择
MAR、MDR、地址线、数据线★★★★地址范围、位数计算
SRAM / DRAM★★★★特点辨析、地址引脚、刷新
DRAM 行列地址、行缓冲★★★★计算、选择
多体低位交叉存储★★★★带宽、体号、体冲突
主存芯片位扩展、字扩展★★★★芯片数量、地址范围
磁盘★★★容量、存取时间
SSD★★原理辨析
Cache 基本原理、命中率★★★★★计算
Cache 三种映射★★★★★地址划分、映射、综合题
Cache 总容量★★★★★高频计算
LRU / FIFO★★★★模拟替换
Cache 写策略★★★★概念辨析
页式虚拟存储器★★★★★地址转换、缺页
TLB★★★★★地址划分、映射
TLB + 页表 + Cache★★★★★综合题
段式、段页式★★★原理比较

资料中的考点追踪也与这个分布非常一致:组相联映射、虚实地址转换、分页缺页、TLB 等多年反复出现。

二、存储器概述:为什么需要存储层次?

2.1 一个存储器有三个互相矛盾的要求

我们希望存储器同时:

  • 速度特别快;
  • 容量特别大;
  • 每 bit 特别便宜。

但现实中做不到。

一般越靠近 CPU:

层次速度容量每 bit 成本
寄存器极快极小极高
Cache很快小高
主存中等较大中等
SSD / 磁盘慢很大低

所以计算机采用多级结构。资料概括得非常重要:

Cache—主存层主要解决 CPU 与主存的速度不匹配,而且调度主要由硬件自动完成。

主存—辅存层主要解决主存容量不足,通过操作系统与硬件共同完成,从而形成虚拟存储器。

而且上层内容本质上是下层内容的一部分副本:

Cache 中的数据来自主存;主存中的活跃内容又来自辅存。

这句话后面理解 Cache、页表和虚拟存储器时非常重要。

三、主存储器最基本的工作过程

这是看起来简单,但后面总线、CPU、Cache 都会继续使用的一套逻辑。

CPU 要读某个地址的数据时:

CPU
 │
 │ 地址
 ▼
MAR
 │
 │ 地址总线
 ▼
主存地址译码器
 │
 ▼
选中某个存储单元
 │
 │ 数据总线
 ▼
MDR
 │
 ▼
CPU

写操作则反过来:

CPU → MDR → 数据总线 → 主存

资料中特别强调:

MAR 位数主要对应可寻址地址空间,MDR 位数对应一次可传送的数据宽度。

例如按字节编址,有 36 位地址:

所以其地址范围为:

如果数据总线是 64 位,则一次能够并行传送:

一个非常常见的混淆

地址线决定“有多少个地址”。

数据线决定“一次能传多少数据”。

不要把二者混起来。

四、存取时间、存取周期、带宽

这几个概念选择题很喜欢互换。

4.1 存取时间

一次读或写真正需要的时间。

比如主存收到有效地址开始,到读出的数据稳定输出为止。

4.2 存取周期

两次独立存储器访问之间允许的最小时间间隔。

一般:

为什么可能大于?

因为读完之后存储器内部还可能需要恢复、再生、刷新或稳定。

所以:

存取时间关注“一次访问多长”;

存取周期关注“多久才能再开始下一次独立访问”。

4.3 存储器带宽

表示单位时间能够传输多少数据。

它不仅取决于存储器本身速度,还与一次能够传多少 bit、总线宽度等有关。

五、SRAM 和 DRAM

这是主存硬件部分最重要的基础。

资料中的核心对比如下。

特点SRAMDRAM
存储元件触发器电容
是否刷新不需要需要
读出非破坏性破坏性
速度快较慢
集成度低高
成本高低
常见用途Cache主存

可以直接从物理结构理解。

5.1 SRAM 为什么快?

SRAM 用类似触发器的稳定状态保存 0、1。

只要不断电,状态就能维持,因此:

不需要刷新;

读一次也不会把信息破坏掉。

缺点是一个 bit 要用较多晶体管,所以面积大、价格高。

因此特别适合:

容量不需要特别大,但一定要快的 Cache。

六、DRAM:这一部分一定要理解

6.1 DRAM 为什么要刷新?

DRAM 用电容是否存有电荷来表示 0 和 1。

但现实中的电容会漏电。

所以即使 CPU 什么都不做,过一段时间,原来的“1”也可能因为电荷泄漏变成无法识别的状态。

因此 DRAM 必须:

定期读出来,再重新写进去。

这就是刷新。

而且 DRAM 本身属于破坏性读出:

一读,原来的电荷状态会受到破坏,所以普通读取之后也必须进行再生。

七、DRAM 地址引脚复用——高频

这是很经典的计算题。

假设一个 DRAM 芯片有:

其中:

意味着需要区分:

个存储位置。

如果像普通地址一样一次把完整地址送进去,就需要 22 根地址线。

但 DRAM 为了减少芯片引脚,把地址拆成:

行地址
+
列地址

例如:

形成:

的二维阵列。

所以只需要 11 根物理地址引脚。

第一次:

11根引脚 → 行地址
            ↓
           RAS

第二次:

同样11根引脚 → 列地址
                ↓
               CAS

也就是说:

22 位逻辑地址没有消失,只是利用相同的 11 根引脚分两次传送。

这叫做行、列地址复用。

八、DRAM 为什么设计成接近正方形?

假设存储阵列容量为:

其中行数为 ,列数为 ,则:

行地址位数:

列地址位数:

因为行列共用地址引脚,所以真正需要的地址引脚数量取:

为了让这个最大值尽量小,就应该让:

也就是阵列尽可能接近正方形。

但还有第二个条件:

DRAM 刷新是按行刷新。

行越多,需要刷新的行越多。

所以资料指出通常希望:

于是最佳思路就是:

行列尽量接近,同时行数不要比列数更多。

这是 2018 年考点追踪中的内容。

九、DRAM 刷新到底刷新什么?

这是很容易想错的地方。

例如:

不是要执行:

次刷新。

而只需要:

次。

因为一次刷新一整行。

也就是:

给出行地址
      ↓
选中整行
      ↓
整行读出并再生

刷新时甚至不需要列地址。

十、DRAM 行缓冲器与突发传输

这一部分和现代内存为什么连续读很快直接相关。

假设一个 DRAM:

每个单元:

当选中一行时,并不是只把一个单元送出来,而是把这一整行加载到行缓冲器。

因此行缓冲器容量为:

一般公式:

一旦行已经打开,后续访问同一行的相邻列就快得多,因此可以连续输出数据,这就是突发传输的重要基础。

可以把 DRAM 想成:

第一次打开一本书到某一页比较慢; 但这一页已经摊开后,连续读取这一页上的内容就非常快。

十一、多模块存储器与低位交叉——高频计算

CPU 比单个存储体快得多。

一个存储体刚开始一次访问后,在接下来的存取周期里暂时不能再次接受新请求。

怎么办?

答案是:

准备多个存储体,轮流访问。

11.1 高位连续编址

例如有 4 个体:

M0:0 ~ n-1
M1:n ~ 2n-1
M2:2n ~ 3n-1
M3:3n ~ 4n-1

连续访问:

0,1,2,3,4,...

前面大量地址都落在 M0。

所以还是不断访问同一个体,无法充分并行。

资料指出这种连续编址本质上仍是顺序访问。

十二、低位交叉编址

现在换一种方式:

地址0 → M0
地址1 → M1
地址2 → M2
地址3 → M3
地址4 → M0
地址5 → M1
...

对于 个存储体:

所以连续地址会均匀分布到不同存储体。

这样:

t=0      M0 开始工作
t=r      M1 开始工作
t=2r     M2 开始工作
t=3r     M3 开始工作
...

就像流水线。

12.1 最重要公式

如果单个存储体存取周期为 ,相邻存储体启动间隔为 ,为了实现无冲突轮流启动,需要:

12.2 资料中的典型题

八体低位交叉存储器:

单体存储周期:

所以启动间隔:

一次传 64 位:

因此稳定后:

得到:

也可以直接:

其中 是每个体一次输出的数据量。资料配套题答案也是 800 MB/s。

注意

低位交叉主要提高的是:

连续访问时的吞吐率 / 带宽。

它并没有 magically 把单个存储体本身的存取周期变短。

十三、体冲突怎么做?

体冲突题不要凭感觉。

先算:

然后逐个模拟请求启动。

若某个体在一个完整存取周期内再次被访问:

该请求必须等待。

如果题目明确说“发生冲突以后后续请求整体延迟”,则后面的启动时间也跟着往后移动。

所以这类题本质不是难算法,而是:

求模 + 时间轴模拟。

十四、主存芯片扩展——一定要会

主存扩展有三个概念:

位扩展、字扩展、字位扩展。

最简单的判断方法:

“宽度不够” → 位扩展。 “地址数量不够” → 字扩展。 两个都不够 → 字位扩展。

十五、位扩展

例如:

芯片:8K × 1 bit
目标:8K × 8 bit

地址数量已经足够:

8K → 8K

但是一个芯片一次只有 1 bit,需要 8 bit。

所以:

片。

连接关系:

A0~A12 ─┬→ 芯片0
         ├→ 芯片1
         ├→ ...
         └→ 芯片7

所有芯片同时选中

芯片0 → D0
芯片1 → D1
...
芯片7 → D7

所有芯片:

  • 地址线相同;
  • 片选相同;
  • 读写控制相同;
  • 数据线分别占一个 bit。

所以是并行工作。

十六、字扩展

例如:

芯片:16K × 8 bit
目标:64K × 8 bit

位宽已经够了。

但地址数量差:

所以需要 4 片。

单片:

因此芯片内部地址需要:

整个 64K:

所以总地址:

高出的:

拿去做片选。

于是:

A15 A14芯片地址范围
0000000H~3FFFH
0114000H~7FFFH
1028000H~BFFFH
113C000H~FFFFH

这正是资料中的例子。

十七、字位扩展的万能计算法

这是我根据资料中的位扩展和字扩展规则整理出的通用解题模板。

目标:

M × W

单片:

m × w

位扩展倍数:

字扩展倍数:

总芯片数:

例如:

目标:64K × 16
芯片:16K × 8

则:

所以:

可以理解成:

一组2片并联 → 构成16K×16
一共4组      → 构成64K×16

十八、磁盘存储器

磁盘不是本章最难,但计算公式非常固定。

磁盘要先理解:

一个盘片
 ├─ 上表面
 └─ 下表面

每个表面
 └─ 一圈圈磁道

磁道
 └─ 划分为扇区

不同盘面相同半径位置的一组磁道组成柱面。

因此磁盘地址通常表示为:

柱面号 + 磁头/盘面号 + 扇区号

18.1 格式化容量

最常考:

资料也指出:

因为格式化需要同步信息、间隙等额外空间。

十九、磁盘存取时间——高频公式

磁盘真正读到数据之前,要做三件事:

1. 磁头移动到目标磁道
      ↓
2. 等待目标扇区转到磁头下面
      ↓
3. 真正传输数据

所以:

资料将这三部分称为磁盘核心存取时间;若算完整响应时间,还可能加入排队延迟和控制器时间。

19.1 平均旋转等待时间

假设转速为 RPM。

转一圈时间:

平均等待半圈:

例如 7200 RPM:

平均等待:

这就是为什么机械磁盘随机访问很慢:不是磁介质本身传数据慢,而是机械寻道 + 等待旋转很耗时间。

二十、SSD

资料中的 SSD 基于 Flash,由一个或多个闪存芯片以及闪存翻译层等组成,不存在机械磁头与盘片。

所以最直观的区别是:

HDD:
寻道 → 等旋转 → 传输

SSD:
电子方式定位 → 访问Flash

因此 SSD 的随机访问性能远好于机械磁盘。

这一节考研中更多是理解和选择题,不需要像 Cache 那样投入大量精力。

二十一、Cache:本章第一核心

现在进入第 3 章最重要部分之一。

Cache 的逻辑其实只有一句:

把 CPU 最近很可能还要访问的主存块复制一份放在高速 SRAM 中。

依据就是局部性原理。

二十二、时间局部性与空间局部性

时间局部性

一个数据刚访问过,那么短时间内很可能还会再次访问。

例如:

for (...) {
    sum += a;
}

变量 sum、循环控制指令会不断重复访问。

空间局部性

刚访问地址 X,那么接下来很可能访问:

X+1
X+2
X+3
...

例如顺序访问数组。

资料特别通过二维数组按行、按列访问说明:即使两个程序实现完全相同的功能,因为内外循环顺序不同,也可能产生完全不同的 Cache 命中情况。

这也是为什么:

for (i)
    for (j)
        a[i][j];

通常比按列跳着访问更符合 C 语言二维数组的空间局部性。

二十三、Cache 为什么按“块”交换?

Cache 不会只从主存拿你当前需要的一个字节。

而是把它所在的整个主存块搬进 Cache。

例如:

一个 Cache 块 = 64B

CPU 要地址 1000。

那么可能直接搬:

地址 960 ~ 1023

这一整块。

因为根据空间局部性:

既然访问 1000,很可能马上还会访问 1001、1002……

这就是“块”的意义。

二十四、Cache 命中与缺失

CPU 每次访存先查 Cache:

CPU给地址
   ↓
查 Cache
 ┌─────────────┐
 │             │
命中          未命中
 │             │
直接读取      访问主存
               ↓
           整块调入Cache
               ↓
           再交给CPU

这个过程由硬件自动完成,对程序员透明。

二十五、Cache 命中率计算

假设命中次数为 ,未命中次数为 ,则:

缺失率:

如果 Cache 访问时间为 ,主存调块损失为 ,且采用资料所说的“先查 Cache,缺失再访问主存”,则:

整理:

这是非常重要的公式。

25.1 资料中的典型例子

Cache 比主存快 5 倍:

命中率:

于是:

不用 Cache 需要:

所以性能变为:

即约提升到原来的 4 倍。

做题特别注意

一定看题目:

Cache 和主存是先后访问还是同时访问。

平均时间公式会因此不同。资料中的主要模型是先 Cache、后主存。

二十六、Cache 映射:整个第 3 章最重要计算之一

先记住三种:

直接映射
全相联映射
组相联映射

难点实际上不是名字,而是:

一个主存块到底允许放到 Cache 的哪些位置?

二十七、直接映射

直接映射规定:

每个主存块只能进入唯一一个 Cache 行。

假设 Cache 有 行:

例如 Cache 有 8 行。

主存块:

0 → 行0
1 → 行1
...
7 → 行7
8 → 行0
9 → 行1
...

因此块 0、8、16、24……都抢 Cache 行 0。

优点:

简单、快、便宜。

缺点:

很容易发生冲突。

二十八、直接映射的地址结构

若按字节编址:

主存地址
┌──────────┬──────────┬────────────┐
│   Tag    │ Cache行号 │   块内偏移   │
└──────────┴──────────┴────────────┘

假设:

  • 主存地址为 位;
  • Cache 数据容量为 字节;
  • 块长为 字节。

Cache 行数:

块内偏移位数:

Cache 行号位数:

Tag 位数:

这三个公式一定要熟练。

二十九、为什么需要 Tag?

假设:

块0  → 行0
块8  → 行0
块16 → 行0

CPU 只看到“行 0”是不够的。

必须知道行 0 当前到底装的是谁。

所以 Cache 行中除了真正的数据,还有:

Tag
有效位
数据块

Tag 就是:

“我现在存的是哪一个主存块?”

三十、资料中的 Cache 容量经典例题

主存:

按字节编址,所以物理地址:

Cache:

8 行
每行 64B
直接映射

块内偏移:

所以:

8 个 Cache 行:

所以行号:

Tag:

于是地址结构:

┌───────────┬───────┬────────┐
│ Tag 19bit │ 行 3bit│偏移6bit │
└───────────┴───────┴────────┘

三十一、Cache “数据容量”和“总容量”不是一回事

每行真正的数据:

但还要保存:

  • 19 位 Tag;
  • 1 位有效位。

因此每行实际需要:

8 行:

所以:

而纯数据容量只是:

这是 Cache 题最容易丢分的地方之一。

如果题目再给出

  • 脏位;
  • LRU 位;
  • 其他控制位;

也要一并加进去。

所以看到“Cache 总容量”四个字,第一反应应该是:

不能只算数据区。

三十二、直接映射主存块号怎么算?

假设访问字节地址:

块大小:

主存块号:

Cache 8 行:

因此去 Cache 第 2 行。

这是整个 Cache 地址题最基础的三步:

然后:

最后:

三十三、全相联映射

全相联相反:

一个主存块可以进入 Cache 中任意一行。

地址就不需要行号字段:

┌───────────────────┬──────────┐
│       Tag         │ 块内地址  │
└───────────────────┴──────────┘

优点:

几乎不存在映射位置造成的冲突。

问题:

CPU 怎么知道它在哪一行?

答案只能是:

把主存块 Tag 和 Cache 里所有行的 Tag 同时比较。

所以如果 Cache 有 1024 行,就需要大量比较电路。

因此:

命中率高,但硬件复杂、查找成本高。

三十四、组相联映射——最重要

这是现代考试最喜欢出的。

组相联是:

组间直接映射,组内全相联。

例如 Cache:

8 行
2 路组相联

每组 2 行。

所以:

主存块先确定唯一的组:

进入该组以后:

可以放在该组任何一路。

34.1 仍用块号 50

4 组:

所以属于:

第 2 组。

如果每组对应连续的两行,则可进入:

第4行
或
第5行

资料的例子就是这个结果。

三十五、组相联地址结构

┌──────────┬────────┬────────────┐
│   Tag    │ 组号    │ 块内偏移    │
└──────────┴────────┴────────────┘

假设:

  • Cache 数据区容量为 ;
  • 块长为 ;
  • 路组相联。

Cache 行数:

组数:

组号位数:

块内偏移:

Tag:

这是组相联大题最核心的公式组。

三十六、三种映射怎么比较?

资料给出的整体规律是:

特征直接映射组相联全相联
放置自由度最低中间最高
冲突概率高中低
命中率较低中较高
比较器开销低中高
硬件复杂度低中高
访问速度快中较慢

不要死记。

从“一个块允许放几个地方”自然就能推出:

允许位置越多
→ 冲突越少
→ 命中率越高
→ 查找越复杂
→ 硬件越贵

三十七、组相联的完整访问过程

资料明确将这个过程列为 2020 年考点。

CPU 给物理地址:

Tag | 组号 | 块内地址

第一步,根据组号选中一个 Cache 组。

第二步,把地址中的 Tag 与这一组所有路的 Tag 并行比较。

第三步,如果:

Tag相同
且
有效位 = 1

则命中。

第四步,根据块内偏移选择块中的具体字节/字。

第五步,如果均未匹配,则 Cache 缺失。

第六步,把对应主存块调进这个组。如果组已满,则执行替换算法。

三十八、比较器数量也是考点

直接映射:

已经通过行号唯一确定行,所以只需要比较一个 Tag。

路组相联:

一组有 行,需要同时比较 个 Tag。

所以:

比较器位宽一般对应 Tag 位数。

资料将其列为 2022 年考点。

三十九、Cache 替换算法

直接映射根本没有选择:

只有唯一一个位置,因此新块来了就覆盖。

所以:

直接映射不需要替换算法。

替换算法主要发生在:

  • 全相联;
  • 组相联。

资料重点给出 RAND、FIFO、LRU。

四十、FIFO

原则:

谁最早装进来,先淘汰谁。

它关心的是:

“什么时候进入 Cache。”

而不关心:

“最近有没有被访问。”

因此一个很热的数据即使刚刚又用了,也可能因为“进入得太早”而被 FIFO 淘汰。

四十一、LRU——重点

LRU:

Least Recently Used 最近最少使用

准确理解:

淘汰距离现在最久没有访问过的块。

例如 3 路 Cache 当前最近使用顺序:

A → 刚访问
C
B → 最久没访问

新块 D 来时:

淘汰 B。

如果随后访问 C,则:

C → 最新
D
A → 最旧

下一次就淘汰 A。

它利用了:

时间局部性。

资料中 LRU 的命中率分析在 2012、2021 出现,替换位相关内容在 2018、2020 出现。

41.1 LRU 做题最好不要死记计数器

手算题直接维护:

MRU  ← 最近使用
...
LRU  ← 最久未使用

每次命中:

把该块提到最前。

每次缺失:

空闲则装入;满了就删最后一个。

比机械模拟硬件计数器稳得多。

资料中的硬件计数模型则使用每行的 LRU 状态记录相对新旧顺序,例如 4 路时每行计数值需要能够表达 4 种相对状态。

四十二、Cache 抖动

资料给出一个很典型的情形。

一个组只有 4 行,但循环访问 5 个映射到同一组的主存块:

1 2 3 4 5 1 2 3 4 5 ...

LRU:

装1
装2
装3
装4

访问5 → 淘汰1
访问1 → 淘汰2
访问2 → 淘汰3
访问3 → 淘汰4
...

结果:

几乎每次都缺失。

这就是典型的抖动。

四十三、Cache 写策略

读 Cache 比较简单。

写的问题在于:

Cache 是主存的副本。CPU 改了 Cache 后,主存怎么办?

因此有一致性问题。

四十四、写直达 Write Through

CPU 写 Cache 时:

Cache ← 新数据
主存  ← 同时写新数据

优点:

Cache 与主存始终一致。

缺点:

每次写都访问主存,很慢。

因此可以加写缓冲区:

CPU → Cache
 └──→ Write Buffer → 慢慢写主存

资料特别指出写缓冲可以缓解速度差,但大量连续写时仍可能饱和。

四十五、回写 Write Back

CPU 写命中时:

只改 Cache
暂时不改主存

等这个 Cache 块以后被替换时,再一次写回主存。

优点:

大幅减少主存写次数。

但问题来了:

怎么知道这个块究竟有没有改过?

所以需要:

Dirty Bit,脏位。

dirty = 0
→ Cache与主存一致
→ 替换时直接扔

dirty = 1
→ Cache被CPU修改过
→ 替换前必须写回主存

所以:

Write Through 通常不需要 dirty bit;

Write Back 必须记录 dirty bit。

四十六、写不命中怎么办?

资料还区分:

Write Allocate

写不命中后,将相应主存块调入 Cache,再让其参与后续访问。

其思想是:

既然现在访问它,根据局部性,未来可能还会继续访问。

Not Write Allocate

写不命中:

直接写主存,不把这一块调入 Cache。

考选择题时一定把:

Write Through / Write Back

与:

Write Allocate / Not Write Allocate

看作两个不同维度的问题。

前者解决:

Cache 写命中后如何保持一致。

后者解决:

Cache 写不命中后要不要把这个块装入 Cache。

四十七、虚拟存储器:本章第二核心

Cache解决:

CPU 太快,主存太慢。

虚拟存储器解决:

程序需要的地址空间可能比物理内存更大。

例如:

程序看到:
0 ~ 4GB 虚拟空间

实际物理内存:
可能只有1GB

程序并不要求全部同时进入主存。

只把当前真正需要的页放进去。

其他页面暂存在磁盘。

因此形成:

CPU
 ↓
虚拟地址
 ↓
地址转换
 ↓
物理地址
 ↓
主存

四十八、页式虚拟存储器

把虚拟地址空间划成固定大小:

虚页。

把物理内存划成相同大小:

页框 / 物理页。

例如页大小:

那么任意地址最低:

就是页内偏移。

四十九、虚拟地址结构——必须一眼会拆

如果虚拟地址 位,页大小:

那么:

┌────────────────┬──────────────┐
│ 虚拟页号 n-p bit │ 页内偏移 p bit │
└────────────────┴──────────────┘

其中:

例如:

32位虚拟地址
4KB页

因为:

所以:

VPN:20 bit
Offset:12 bit

五十、虚拟地址为什么不能直接访问内存?

因为虚页 5 不一定放在物理页框 5。

例如:

虚页0 → 页框7
虚页1 → 页框2
虚页2 → 不在内存
虚页3 → 页框9

必须有一张表:

页表 Page Table

记录:

虚拟页号 → 物理页框号

五十一、页表项有什么?

资料重点列出了:

字段作用
物理页号页面当前在哪个物理页框
有效位当前是否在主存
脏位是否被修改
引用位是否最近使用过

有效位尤其重要:

Valid = 1
→ 页面在主存

Valid = 0
→ 页面不在主存
→ 缺页异常

五十二、虚拟地址 → 物理地址全过程

资料把这一过程作为多年的高频考点。

虚拟地址:

VPN | Offset

第一步:取出 VPN。

第二步:VPN 作为页表索引。

第三步:找到页表项。

第四步:检查有效位。

如果:

Valid=1

得到物理页号 PPN。

第五步:

PPN | Offset

拼接成为物理地址。

注意最重要的一点:

页内偏移不变!

即:

VA : VPN | Offset
           ↓↓↓↓↓↓
PA : PPN | Offset

只有页号发生翻译。

五十三、为什么页内偏移不变?

因为:

一个虚页整体被放进某一个物理页框。

页内部数据之间的相对位置不会改变。

如果虚页中的第 123 个字节进入物理页框,那么它还是物理页框里的第 123 个字节。

因此:

这是地址转换题非常关键的检查条件。

五十四、缺页异常发生什么?

如果页表:

Valid = 0

说明这一页不在内存。

过程大致为:

CPU访问
 ↓
发现页不在主存
 ↓
产生缺页异常
 ↓
操作系统介入
 ↓
从磁盘找到页面
 ↓
寻找空闲物理页框
 ↓
若没有空闲页框 → 页面置换
 ↓
必要时写回脏页
 ↓
新页调入主存
 ↓
修改页表
 ↓
重新执行相关访问

资料明确指出缺页处理由操作系统完成,换出页面是否需要写回磁盘取决于脏位。

一个极重要区别

Cache Miss:

正常硬件事件。

Page Fault:

异常,需要操作系统介入,而且可能访问磁盘,代价极大。

五十五、为什么需要 TLB?

没有 TLB 时,一次普通访存:

CPU
 ↓
先访问主存页表
 ↓
得到物理页号
 ↓
再次访问主存
 ↓
真正的数据

本来一次主存访问,现在至少变两次。

效率太低。

怎么办?

把最近使用的页表项放入一个高速小缓存:

TLB,Translation Lookaside Buffer

也就是快表。

五十六、TLB 到底缓存什么?

这是特别容易混淆的地方。

Cache 存:

主存中的数据块/指令块。

TLB 存:

页表项,即虚拟页号到物理页号的转换关系。

所以:

Cache = 数据的缓存
TLB   = 地址翻译结果的缓存

配套选择题也专门考过这个区别。

五十七、TLB 为什么采用相联存储?

CPU 拿到 VPN 时,希望:

一次快速判断“这个 VPN 在不在 TLB”。

因此 TLB 常采用:

  • 全相联;
  • 组相联。

全相联 TLB 中:

Tag 基本就是完整 VPN。

组相联中:

VPN
=
TLB Tag + TLB组号

资料把 TLB 映射和地址字段分析列为 2016、2021 年考点。

五十八、TLB 命中与缺失千万别混淆

TLB Miss 只表示:

“翻译结果没缓存在 TLB。”

它不等于:

页面不在内存。

因此:

TLB Miss
 ↓
查主存页表
 ↓
 ┌──────────────┐
 │              │
页表命中      页表无效
 │              │
得到PPN       Page Fault

这是本章最容易混淆的一句话:

五十九、TLB + 页表 + Cache:综合题核心

这一块建议你以后遇到任何题都严格按照同一条流水线做。

假设 CPU 给出虚拟地址。

第一步:拆虚拟地址

VA
=
VPN | Page Offset

其中:

第二步:查询 TLB

使用 VPN 查询 TLB。

TLB 命中

直接拿到 PPN。

TLB 缺失

访问主存中的页表。

第三步:查询页表

如果页表有效:

得到 PPN,同时可将页表项填入 TLB。

如果无效:

缺页异常 → 操作系统 → 磁盘。

第四步:形成物理地址

这里的符号表示拼接。

第五步:再用物理地址访问 Cache

如果 Cache 块长:

则低:

位为 Cache 块内偏移。

第六步:根据 Cache 映射方式取组号/行号

例如组相联:

第七步:Tag 比较

Tag匹配 + Valid=1
→ Cache Hit

否则:

Cache Miss
→ 从主存调入块

这整套流程就是资料特别强调的 “TLB + Cache 存储系统地址转换”。2024 年的考点追踪也出现了这一过程。

六十、TLB、Page、Cache 三种命中关系

资料专门总结过这张逻辑表。

TLBPageCache是否可能
HitHitHit✓
HitHitMiss✓
MissHitHit✓
MissHitMiss✓
MissMissMiss✓
HitMiss任意✗
任意MissHit✗

背后只有两条逻辑链。

第一条

TLB 中有有效页表项:

说明对应页面必然已经在主存。

因此:

第二条

页面根本不在主存:

Cache 作为主存内容的副本,自然也不可能保存这个页面对应的数据。

因此:

理解这两句话,就不用死背组合表。

六十一、Cache 和页表地址字段不要混

这一点综合题特别重要。

假设:

页大小 = 4KB
Cache块 = 64B

那么页内偏移:

Cache 块内偏移:

二者不是同一个东西。

虚实地址转换保持的是:

12 bit Page Offset

而 Cache 访问使用:

最低6 bit作为Cache Block Offset

所以:

页 ≠ Cache 块。

通常一个页包含很多个 Cache 块。

例如:

即一个 4KB 页面对应 64 个 Cache 块。

六十二、页大小大还是小?

资料在本章开头就把这个问题列为思考题。

本质上是权衡。

页大:

一次从磁盘调入的数据更多,页表项更少,页表更小,也容易利用空间局部性;但可能把很多暂时没用的数据也调进来,并增大页内浪费。

页小:

内部浪费较小,分配更灵活;但页数量增加,页表更大,页表/TLB 管理压力提高。

所以不能说:

越大越好。

也不能说:

越小越好。

它是一个典型的工程折中。

六十三、段式虚拟存储器

分页按照:

固定大小。

分段则按照:

程序逻辑结构。

例如:

代码段
数据段
栈段
...

虚拟地址:

段号 | 段内偏移

段表项包含类似:

段基址
段长
有效位
...

地址转换:

段号
 ↓
查段表
 ↓
得到段基址
 ↓
检查段内地址是否合法
 ↓
段基址 + 段内地址
 ↓
物理地址

资料指出分段的优点是逻辑结构清晰,便于共享和保护;缺点是段长可变,容易产生外部碎片。

六十四、分页与分段的本质区别

页段
固定大小可变大小
物理划分思想逻辑划分思想
对程序员透明体现程序逻辑结构
容易内部碎片容易外部碎片
共享保护语义弱一些更适合逻辑共享保护

考试里不要只记:

页固定、段可变

更深层本质是:

页为了方便物理内存管理;段为了匹配程序逻辑结构。

六十五、段页式

段页式就是把两者叠起来:

程序
 ↓
先按逻辑分段
 ↓
每个段内部再分页

虚拟地址:

段号 | 段内页号 | 页内偏移

地址转换:

段号
 ↓
段表
 ↓
找到该段的页表
 ↓
段内页号
 ↓
页表
 ↓
物理页号
 ↓
PPN | 页内偏移

好处:

有段的逻辑共享、保护能力;

又有页式固定大小分配的便利。

缺点:

地址转换层次更多,开销更大。

六十六、Cache 和虚拟存储器到底有什么共同点?

这个问题非常适合把整个第 3 章连起来。

资料总结两者都依赖:

局部性、分块、地址映射、替换策略等。

但它们解决的问题不同:

Cache虚拟存储器
解决 CPU—主存速度差解决主存容量不足
Cache ↔ 主存主存 ↔ 磁盘
块较小页通常较大
缺失代价相对低缺页代价极高
主要硬件管理OS + 硬件协作
对程序员透明对应用程序员透明

一句话:

Cache 让主存“看起来更快”;虚拟存储让主存“看起来更大”。

六十七、第 3 章综合题万能解题流程

以后遇到一道同时出现:

虚拟地址
页表
TLB
Cache
主存

不要直接盯着二进制乱算。

固定顺序:

A. 先处理页面

页大小:

立即得到:

拆:

VPN | Page Offset

B. TLB

根据 TLB 是全相联还是组相联,拆 VPN。

查询:

Tag + Valid

C. 页表

TLB Miss:

页表基址 + VPN×页表项大小

找到 PTE。

看:

Valid
PPN
Dirty
...

D. 形成物理地址

PPN | Page Offset

E. 再处理 Cache

块大小:

得到:

F. 算 Cache 组数

路组相联:

G. 算组号位数

H. 算 Tag

最后才:

查组 → Tag 比较 → 判断 Hit/Miss → 必要时替换。

这是我最建议你把它练成“肌肉记忆”的流程。

六十八、本章最容易错的十个地方

  1. 存取时间 ≠ 存取周期,通常存取周期更大。

  2. SRAM 不刷新,DRAM 要刷新;DRAM 还是破坏性读出。

  3. DRAM 的行列地址复用是复用物理引脚,不是把完整地址位数减少了。

  4. DRAM 刷新是按整行刷新,不是每个存储单元单独刷新。

  5. 低位交叉:

它主要提高吞吐率,不是缩短单体存取周期。

  1. 位扩展增加数据位宽;字扩展增加地址数量。

  2. Cache 总容量不能只算数据,还可能有 Tag + Valid + Dirty + 替换信息。

  3. 直接映射没有替换选择,所以不需要替换算法。

  4. TLB Miss 不等于 Page Fault。

  5. 页内偏移和 Cache 块内偏移不是一个概念。

六十九、最后把整章压缩成一张逻辑图

                        存储系统
                           │
          ┌────────────────┴────────────────┐
          │                                 │
       为什么分层?                       具体怎么实现?
          │                                 │
   速度/容量/成本矛盾             ┌─────────┴──────────┐
          │                       │                    │
          ▼                       ▼                    ▼
  Cache—主存—辅存              主存硬件              外存
          │                       │                    │
          │                 SRAM / DRAM          HDD / SSD
          │                       │                    │
          │              地址复用/刷新/行缓冲     容量/存取时间
          │
   ┌──────┴──────────────────────┐
   │                             │
 Cache                       虚拟存储
   │                             │
解决速度                     解决容量
   │                             │
局部性                        局部性
   │                             │
主存块                         页面
   │                             │
映射                           页表
   │                             │
直接/全相联/组相联              TLB
   │                             │
替换                           缺页
FIFO/LRU                       │
   │                             │
写策略                    段式 / 段页式
   │
命中率/平均访存时间

如果为了 408 考试得分来安排这一章的复习时间,建议优先把四大模块彻底练熟:1 Cache 地址划分与总容量;2 TLB + 页表 + Cache 综合地址转换;3 主存芯片字/位扩展与地址范围;4 低位交叉存储器带宽和体冲突。 其中前两个是这一章真正的核心,资料本身也明确将 Cache、虚拟存储器以及二者结合的地址翻译列为重点。

接下来再学 DRAM 地址复用、刷新和行缓冲,最后用磁盘、SSD、存储器分类这些相对独立的知识补全选择题即可。

On this page

一、第 3 章考点地图二、存储器概述:为什么需要存储层次?2.1 一个存储器有三个互相矛盾的要求三、主存储器最基本的工作过程一个非常常见的混淆四、存取时间、存取周期、带宽4.1 存取时间4.2 存取周期4.3 存储器带宽五、SRAM 和 DRAM5.1 SRAM 为什么快?六、DRAM:这一部分一定要理解6.1 DRAM 为什么要刷新?七、DRAM 地址引脚复用——高频八、DRAM 为什么设计成接近正方形?九、DRAM 刷新到底刷新什么?十、DRAM 行缓冲器与突发传输十一、多模块存储器与低位交叉——高频计算11.1 高位连续编址十二、低位交叉编址12.1 最重要公式12.2 资料中的典型题注意十三、体冲突怎么做?十四、主存芯片扩展——一定要会十五、位扩展十六、字扩展十七、字位扩展的万能计算法十八、磁盘存储器18.1 格式化容量十九、磁盘存取时间——高频公式19.1 平均旋转等待时间二十、SSD二十一、Cache:本章第一核心二十二、时间局部性与空间局部性时间局部性空间局部性二十三、Cache 为什么按“块”交换?二十四、Cache 命中与缺失二十五、Cache 命中率计算25.1 资料中的典型例子做题特别注意二十六、Cache 映射:整个第 3 章最重要计算之一二十七、直接映射二十八、直接映射的地址结构二十九、为什么需要 Tag?三十、资料中的 Cache 容量经典例题三十一、Cache “数据容量”和“总容量”不是一回事如果题目再给出三十二、直接映射主存块号怎么算?三十三、全相联映射三十四、组相联映射——最重要34.1 仍用块号 50三十五、组相联地址结构三十六、三种映射怎么比较?三十七、组相联的完整访问过程三十八、比较器数量也是考点三十九、Cache 替换算法四十、FIFO四十一、LRU——重点41.1 LRU 做题最好不要死记计数器四十二、Cache 抖动四十三、Cache 写策略四十四、写直达 Write Through四十五、回写 Write Back四十六、写不命中怎么办?Write AllocateNot Write Allocate四十七、虚拟存储器:本章第二核心四十八、页式虚拟存储器四十九、虚拟地址结构——必须一眼会拆五十、虚拟地址为什么不能直接访问内存?五十一、页表项有什么?五十二、虚拟地址 → 物理地址全过程五十三、为什么页内偏移不变?五十四、缺页异常发生什么?一个极重要区别五十五、为什么需要 TLB?五十六、TLB 到底缓存什么?五十七、TLB 为什么采用相联存储?五十八、TLB 命中与缺失千万别混淆五十九、TLB + 页表 + Cache:综合题核心第一步:拆虚拟地址第二步:查询 TLBTLB 命中TLB 缺失第三步:查询页表第四步:形成物理地址第五步:再用物理地址访问 Cache第六步:根据 Cache 映射方式取组号/行号第七步:Tag 比较六十、TLB、Page、Cache 三种命中关系第一条第二条六十一、Cache 和页表地址字段不要混六十二、页大小大还是小?六十三、段式虚拟存储器六十四、分页与分段的本质区别六十五、段页式六十六、Cache 和虚拟存储器到底有什么共同点?六十七、第 3 章综合题万能解题流程A. 先处理页面B. TLBC. 页表D. 形成物理地址E. 再处理 CacheF. 算 Cache 组数G. 算组号位数H. 算 Tag六十八、本章最容易错的十个地方六十九、最后把整章压缩成一张逻辑图