Skip to main content
本章按“存储层次 → 主存储器 → 外部存储器 → Cache → 虚拟存储器”整理存储系统。复习时先建立层次结构和地址映射的整体框架,再重点掌握容量、地址位数、存取时间和命中率等计算。
计算题的核心线索始终是“容量决定地址位数,地址划分决定映射关系”。遇到 Cache 或虚拟存储器题目时,先写出地址字段,再代入公式。

存储器概述

存储层次与分类

从 CPU 到外部存储器,典型层次为:越靠近 CPU 的层次速度越快、单位容量成本越高、容量越小。层次结构能够同时获得接近高速层的访问速度和接近低速层的容量与价格。
命中率表示访问落在高速层中的比例:H=NhitNhit+NmissH = \frac{N_{\text{hit}}}{N_{\text{hit}} + N_{\text{miss}}}若一次访问命中时耗时 tht_h,未命中时总耗时 tmt_m,则平均访问时间为:Tavg=H⋅th+(1−H)⋅tmT_{\text{avg}} = H \cdot t_h + (1-H) \cdot t_m
tmt_m 表示一次未命中访问的总时间,不一定是“缺失代价”。若题目给出的未命中时间仅为额外开销,应写成 Tavg=th+(1−H)⋅tmiss_penaltyT_{\text{avg}} = t_h + (1-H) \cdot t_{\text{miss\_penalty}}。

局部性原理

  • 时间局部性:刚被访问过的数据或指令,在后续访问中很可能再次被访问。循环变量、循环体代码是典型例子。
  • 空间局部性:刚被访问过的存储单元,其相邻单元在后续访问中很可能被访问。顺序访问数组、顺序执行指令是典型例子。
Cache 之所以有效,是因为程序同时具有时间局部性和空间局部性。若题目询问“为什么一次调入一个数据块”,应从空间局部性解释。

主存储器

半导体随机存取存储器

SRAM 的“静态”指只要不断电,数据就能稳定保持,并不表示访问时不需要时钟或控制信号。
DRAM 用电容保存数据,电荷会因漏电逐渐丢失,因此必须在规定时间内逐行读出并再生,这个过程称为刷新。刷新的关键结论:
  • 刷新以行为单位,不需要列地址,也不需要 CAS。
  • 刷新一遍所需的操作次数等于 DRAM 的行数。
  • RAS-only 刷新由外部提供行地址;自动刷新由片内刷新计数器产生行地址。
  • 刷新周期通常指全部存储单元必须完成一次刷新的最大时间,例如某器件规定为 64 ms64\text{ ms}。
若共有 RR 行,刷新周期为 TrefreshT_{\text{refresh}},则平均刷新间隔为:trefresh_avg=TrefreshRt_{\text{refresh\_avg}} = \frac{T_{\text{refresh}}}{R}例如某 DRAM 有 2048 行,刷新周期为 64 ms64\text{ ms},则在 64 ms64\text{ ms} 内需要完成 2048 次行刷新,平均每隔64 ms2048=31.25 μs\frac{64\text{ ms}}{2048} = 31.25\ \mu\text{s}刷新一行。三种刷新安排:
DRAM 芯片通常由存储体、地址译码器、I/O 电路、片选控制逻辑和读写控制线组成。DRAM 芯片根据图中引脚和存储阵列可以得到以下结论:
  1. 芯片有 11 根地址线 A0∼A10A_0 \sim A_{10} 和 4 根数据线 D0∼D3D_0 \sim D_3。在 RAS 和 CAS 控制下,同一组地址引脚分时传送行地址和列地址。
  2. 存储阵列为 2048×2048×42048 \times 2048 \times 4 位,共有 4 个位平面。行地址和列地址各 11 位,同一行、列交叉处的 4 个位平面同时读写。
  3. 刷新时不需要列寻址。对于 RAS-only 刷新,外部提供行地址;对于自动刷新,片内刷新计数器产生行地址。
  4. 芯片共有 2048 行,因此将全部存储单元刷新一遍需要 2048 次行刷新。
该芯片的总位数为:2048×2048×4=16 Mbit=2 MiB2048 \times 2048 \times 4 = 16\text{ Mbit} = 2\text{ MiB}
为减少地址引脚,行地址位数和列地址位数应尽量接近;在其他条件相同时,减少行数有利于降低刷新开销,但需要结合列地址位数和存储阵列结构综合考虑。

存储器芯片的扩展

设目标存储器规格为“目标字数 × 目标字长”,单片芯片规格为“单片字数 × 单片字长”。字向片数=目标字数单片字数\text{字向片数} = \frac{\text{目标字数}}{\text{单片字数}}位向片数=目标字长单片字长\text{位向片数} = \frac{\text{目标字长}}{\text{单片字长}}总片数=字向片数×位向片数\text{总片数} = \text{字向片数} \times \text{位向片数}
不要把“字扩展”和“位扩展”的方向弄反:字扩展增加“有多少个字”,位扩展增加“每个字有多少位”。
用 4K×84\text{K} \times 8 位的芯片组成 16K×1616\text{K} \times 16 位的主存。
  • 位向片数:16÷8=216 \div 8 = 2
  • 字向片数:16K÷4K=416\text{K} \div 4\text{K} = 4
  • 芯片总数:2×4=82 \times 4 = 8
目标主存共有 16K16\text{K} 个存储单元,因此需要 14 根地址线;每个存储字为 16 位,因此需要 16 根数据线。

多模块存储器

对按字编址的交叉存储器,若共有 mm 个模块,则:模块号=单元地址 mod m\text{模块号} = \text{单元地址} \bmod m
交叉编址示例
轮流启动方式设模块存取周期为 TT,数据总线传送一个字的周期为 rr。为了避免下一个模块的数据已经准备好时总线仍被占用,模块数应满足:m≥Trm \geq \frac{T}{r}若题目要求最小整数模块数,则应取:mmin⁡=⌈Tr⌉m_{\min} = \left\lceil \frac{T}{r} \right\rceil连续读取 mm 个字所需时间为:tm=T+(m−1)rt_m = T + (m-1)r
第一个字需要等待模块完成一次存取,后续 m−1m-1 个字可以按总线周期依次传送。
同时启动方式
  • 多个模块同时开始读或写。
  • 所有模块一次并行读写的总位数必须能够由存储器数据总线一次传送。
  • 并行访问通常以连续若干字节为单位,并受到数据对齐要求约束。
连续编址时,连续地址集中在同一模块,CPU 顺序读取时仍需等待该模块完成一次存取,其他模块无法有效接续工作。交叉编址时,连续地址分散在不同模块。模块 0 正在存取时,可以启动模块 1;模块 1 正在存取时,可以启动模块 2。各模块的操作在时间上重叠,因此能提高连续访问时的吞吐率。

外部存储器

磁盘存储器

设备组成:
  • 磁盘驱动器:驱动盘片旋转,并控制磁头在盘面上读写数据。
  • 磁盘控制器:连接磁盘驱动器与主机,接收并解析 CPU 的命令,发送控制信号并监控运行状态。
  • 盘片:真正保存数据的磁性存储介质。
存储区域的层次:
磁盘读写的最小单位通常是扇区。一次读写一个扇区时,即使只需要其中少量字节,也必须访问整个扇区。
磁盘地址通常由“柱面号、盘面号、扇区号”组成:访问顺序通常为:
同一柱面内更换磁头不需要重新寻道,因此磁盘地址通常先给出柱面号,再给出盘面号。
非格式化容量表示磁记录表面理论上可利用的磁化单元数量:C非格式化=记录面数×柱面数×每磁道磁化单元数C_{\text{非格式化}} = \text{记录面数} \times \text{柱面数} \times \text{每磁道磁化单元数}格式化容量表示按扇区、地址和校验信息等格式组织后,实际可供用户使用的容量:C格式化=记录面数×柱面数×每道扇区数×每扇区字节数C_{\text{格式化}} = \text{记录面数} \times \text{柱面数} \times \text{每道扇区数} \times \text{每扇区字节数}
对低密度磁盘,各磁道扇区数相同,由于外圈周长更长,内圈位密度通常高于外圈。高密度磁盘则尽量使各磁道位密度接近,外圈可设置更多扇区,从而提高整盘容量。
磁盘的完整响应时间通常包括:T响应=T排队+T控制器+T寻道+T旋转等待+T传输T_{\text{响应}} = T_{\text{排队}} + T_{\text{控制器}} + T_{\text{寻道}} + T_{\text{旋转等待}} + T_{\text{传输}}磁盘存取时间通常只计算后三项:T存取=T寻道+T旋转等待+T传输T_{\text{存取}} = T_{\text{寻道}} + T_{\text{旋转等待}} + T_{\text{传输}}设磁盘转速为 nn 转/分钟,则旋转一周的时间为:T旋转=60n sT_{\text{旋转}} = \frac{60}{n}\text{ s}平均旋转等待时间约为旋转半周:T旋转等待平均=30n sT_{\text{旋转等待平均}} = \frac{30}{n}\text{ s}平均存取时间一般写为:T存取平均=T寻道平均+T旋转等待平均+T传输T_{\text{存取平均}} = T_{\text{寻道平均}} + T_{\text{旋转等待平均}} + T_{\text{传输}}
计算题中若给出“平均寻道时间”,应直接使用;若给出“最大寻道时间”和“最小寻道时间”,再根据题意判断应取平均值还是最坏值。
RAID7 通常指带有实时操作系统和 Cache 的厂商增强型磁盘阵列,不是与 RAID0~RAID6 完全同维度的标准分级。复习时按指定教材口径掌握,不建议与前面各级只按“冗余方式”横向比较。
固态硬盘基于 Flash 等半导体存储介质,没有机械寻道和旋转等待。基本读写单位:
  • 读操作以页为单位。
  • 写操作以页为单位。
  • 擦除操作以块为单位,通常一个块包含多个页。
Flash 通常需要先擦除再写入,因此会产生写放大。控制器通过闪存转换层(FTL)、磨损均衡和垃圾回收等机制管理物理块,并延长 SSD 的寿命。

Cache

Cache 的基本原理

Cache 以数据块为单位把主存中的连续数据调入高速缓存。主存和 Cache 之间以块为单位交换数据,CPU 与 Cache 之间通常以字或字节为单位访问。
每一行通常需要:
Cache 利用程序局部性工作:命中时直接返回数据,未命中时再从主存调入数据块。

映射方式

主存中的每个块只能映射到唯一的 Cache 行:Cache 行号=主存块号 mod Cache 总行数\text{Cache 行号} = \text{主存块号} \bmod \text{Cache 总行数}地址结构为:
  • 查找时只需要比较一个标记,硬件简单、速度快。
  • 映射位置固定,块冲突概率最高,空间利用率最低。
主存中的任意一个块都可以放入任意一个 Cache 行:
  • 块冲突概率最低,Cache 空间利用率高。
  • 需要同时比较所有行的标记,比较器数量多、硬件开销大。
Cache 先划分成若干组,主存块映射到唯一的一组,但可以放入该组中的任意一行:Cache 组号=主存块号 mod Cache 组数\text{Cache 组号} = \text{主存块号} \bmod \text{Cache 组数}地址结构为:若每组有 kk 行,则称为 kk 路组相联映射,它是直接映射和全相联映射的折中。

替换算法

直接映射不需要选择被替换行;全相联和组相联映射在发生冲突时可以按题目指定的算法选择被替换行。

写策略

写分配不是“先写主存,再调入 Cache”。其关键动作是“把块调入 Cache 后写入”。

容量与地址位数

Cache 数据区的行数可由容量和块大小确定:Cache 行数=Cache 数据区容量每个数据块的大小\text{Cache 行数} = \frac{\text{Cache 数据区容量}}{\text{每个数据块的大小}}若题目要求计算包括目录信息在内的总容量,应把每行的数据位、标记位和控制位一起计入:CCache=行数×(数据位+标记位+有效位+脏位)+C替换信息C_{\text{Cache}} = \text{行数} \times \left(\text{数据位} + \text{标记位} + \text{有效位} + \text{脏位}\right) + C_{\text{替换信息}}
脏位只在回写策略中存在;替换信息不一定按行计算,可能按组或每种算法单独维护。LRU 位宽必须以教材或题目给出的实现为准,不能一律写成 log⁡2(组内块数)\log_2(\text{组内块数})。
设主存地址为 AA 位,数据块大小为 BB 字节,Cache 数据区大小为 CC 字节。
  • 块内地址位数:
b=log⁡2Bb = \log_2 B
  • Cache 数据块总数与行数:
L=CBL = \frac{C}{B}
  • 直接映射的 Cache 行号位数:
r=log⁡2Lr = \log_2 L
  • kk 路组相联的组数为 S=L/kS=L/k,组号位数为:
s=log⁡2Ss = \log_2 S
  • 直接映射的标记位数:
t=A−b−rt = A - b - r
  • 组相联映射的标记位数:
t=A−b−st = A - b - s
  • 全相联映射的标记位数:
t=A−bt = A - b
某计算机主存地址为 32 位,Cache 数据区容量为 32 KB32\text{ KB},块大小为 64 B64\text{ B},采用四路组相联映射。
  1. 块内地址位数:64=2664=2^6,所以块内地址为 6 位。
  2. Cache 数据块数:32 KB÷64 B=51232\text{ KB} \div 64\text{ B}=512。
  3. Cache 组数:512÷4=128=27512 \div 4=128=2^7,所以组号为 7 位。
  4. 标记位数:32−6−7=1932-6-7=19 位。
地址结构为:

Cache 性能计算

设命中率为 HH,命中时间为 thitt_{\text{hit}},未命中需要额外付出缺失代价 tmiss_penaltyt_{\text{miss\_penalty}},则:Tavg=thit+(1−H)⋅tmiss_penaltyT_{\text{avg}} = t_{\text{hit}} + (1-H) \cdot t_{\text{miss\_penalty}}例如,Cache 命中时间为 1 个时钟周期,缺失代价为 100 个时钟周期,命中率为 95%,则:Tavg=1+0.05×100=6T_{\text{avg}} = 1 + 0.05 \times 100 = 6平均每次访问需要 6 个时钟周期。
要先看清题目给出的是“未命中时的总时间”还是“未命中相对于命中额外增加的代价”,两种写法代入方式不同。

虚拟存储器

页式虚拟存储器

虚拟存储器把程序划分成固定大小的页,把主存划分成同样大小的页框或物理页。页和页框大小相同,因此页内偏移在地址转换前后保持不变。虚拟页号到物理页号的映射由页表保存。页表项通常还包含有效位、访问位、修改位、保护位等信息。
页内地址字段的位数由页大小决定。虚拟地址和物理地址的页内偏移相同,因此地址转换主要替换页号部分。
快表(TLB)是由高速 SRAM 构成的地址转换缓存,它缓存的是页表项,不是程序数据。一次访问大致经过以下步骤:
  1. CPU 用虚拟页号查询 TLB。
  2. TLB 命中时,直接获得物理页号,与页内地址拼接得到物理地址。
  3. TLB 未命中时,访问主存中的页表。
  4. 页表项有效时,把页表项填入 TLB,再完成地址转换。
  5. 页表项无效时产生缺页异常,由操作系统把页面调入主存,更新页表和 TLB,再重新执行相关指令。
TLB 命中只说明“地址转换信息已命中”,不代表 Cache 中的数据一定命中。TLB 未命中也不一定发生缺页,还可能只是在页表中找到但 TLB 中没有缓存。
若题目给出 TLB 命中率和主存访问时间,可按访问路径计算有效访问时间。不访问 Cache 时,设 TLB 查询时间为 tTLBt_{\text{TLB}},一次主存访问时间为 tmt_m,TLB 命中率为 hh:TEAT=h(tTLB+tm)+(1−h)(tTLB+2tm)T_{\text{EAT}} = h(t_{\text{TLB}} + t_m) + (1-h)(t_{\text{TLB}} + 2t_m)其中 TLB 未命中时需要访问主存中的页表取得页表项,再访问主存取得目标数据。多级页表通过分级存储页表项,避免为整个虚拟地址空间准备一张连续大页表。二级页表的虚拟地址可以写成:具体页号位数由虚拟地址位数、页大小和每级页表项数量共同决定。

段式与段页式虚拟存储器

段是按照程序的逻辑结构划分的可变长区域。由于段长度可变,段表项除了给出段基址,还必须给出段长,并在访问时进行越界检查。段式管理便于按程序逻辑共享和保护,但会产生外部碎片。
考试中要区分“段内地址”和“页内地址”:段内地址的位数取决于段的最大长度,页内地址的位数取决于页大小。
段页式管理先把程序按逻辑划分成段,再把每个段划分成固定大小的页。
地址转换过程通常为:
  1. 用段号查询段表,得到该段的页表起始地址。
  2. 用段内页号查询页表,得到物理页号。
  3. 将物理页号与页内地址拼接,得到物理地址。
段页式结合了分段便于逻辑管理和分页减少外部碎片的优点,但需要多次查表,地址转换开销较大。

公式与易错点速查

  • SRAM 与 DRAM:SRAM 不需要刷新,DRAM 是破坏性读出并需要定时刷新。
  • 字扩展与位扩展:字扩展增加存储单元数量,位扩展增加每个存储单元的数据位数。
  • 连续编址与交叉编址:连续编址的高位是模块号,交叉编址的低位是模块号。
  • RAID4 与 RAID5:RAID4 使用专用校验盘,RAID5 将校验块分散到各磁盘。
  • 写分配与非写分配:写分配先把主存块调入 Cache,再写入;非写分配直接写主存。
  • 全写与回写:全写法同时更新 Cache 和主存,回写法只更新 Cache 并依赖脏位。
  • TLB 与 Cache:TLB 缓存地址转换信息,Cache 缓存程序数据。
  • TLB 未命中与缺页:TLB 未命中只表示转换项不在 TLB 中;只有页不在主存时才是缺页。
Last modified on September 22, 2026