Skip to content
TechMind

4 、存储器


一、存储系统概述🧀

现代计算机通常以存储器为中心。CPU、I/O 设备和外部存储器通过总线与主存交换程序和数据。

1、存储器层次🧀

从靠近 CPU 到远离 CPU,典型存储层次为:

\[ \text{寄存器}\rightarrow\text{Cache}\rightarrow\text{主存}\rightarrow\text{辅存} \]
层次 典型器件 速度 容量 单位成本
寄存器 CPU 内部寄存器 最快 最小 最高
Cache SRAM 很快 较小 高
主存 DRAM 中等 较大 中等
辅存 SSD、磁盘 较慢 最大 最低

越靠近 CPU,速度越快、容量越小、单位成本越高。存储层次利用程序的时间局部性和空间局部性,在成本可控的前提下尽量接近高速存储器的性能。

2、存储器分类🧀

分类依据 类型
存储介质 半导体、磁表面、光存储
存取方式 随机存取、顺序存取、直接存取、相联存取
是否可改写 读写存储器、只读存储器
断电后能否保存 易失性、非易失性
系统层次 寄存器、Cache、主存、辅存
  • 随机存取:任意单元的访问时间与地址无关,如主存。
  • 顺序存取:必须按顺序经过前面的记录,如磁带。
  • 直接存取:先定位到区域,再在区域内顺序查找,如磁盘。
  • 相联存取:根据内容而不是地址查找,如 Cache 中的标记比较。

3、性能指标🧀

指标 含义
存取时间 \(T_A\) 发出访问请求到数据可用所需的时间
存取周期 \(T_M\) 连续启动两次独立存储操作之间允许的最短时间,通常 \(T_M\geq T_A\)
存储带宽 单位时间内能够传输的数据量

若每个存取周期传输 \(W\) 位数据,理想带宽为:

\[ \boxed{B=\frac{W}{T_M}} \]

二、主存的组织与编址🧀

1、存储单元、MAR 与 MDR🧀

存储体由许多存储单元组成,每个存储单元又由若干存储元件组成。每个存储单元拥有唯一地址。

  • MAR:存储器地址寄存器,保存本次访问的地址。
  • MDR:存储器数据寄存器,保存读出的数据或准备写入的数据。

设 MAR 为 \(m\) 位、MDR 为 \(n\) 位,则主存最多包含 \(2^m\) 个 \(n\) 位存储字:

\[ \boxed{\text{容量}=2^m\times n\ \text{bit}} \]
单位 换算
bit(b) 最小信息单位
Byte(B) \(1\,\text{B}=8\,\text{bit}\)
KB \(1\,\text{KB}=2^{10}\,\text{B}\)
MB \(1\,\text{MB}=2^{20}\,\text{B}\)
GB \(1\,\text{GB}=2^{30}\,\text{B}\)
TB \(1\,\text{TB}=2^{40}\,\text{B}\)

2、编址单位🧀

编址方式 一个地址对应的数据量
按字节编址 \(1\,\text{B}=8\,\text{bit}\)
按半字编址 半个机器字,常见为 2 B
按字编址 一个机器字,常见为 4 B 或 8 B,取决于体系结构

做容量题必须先确定一个地址对应多少字节。同样是 \(m\) 位地址,按字节编址与按字编址得到的总字节数可能不同。

3、二维译码🧀

若有 \(n\) 位地址,一维译码需要选择 \(2^n\) 条字线。把地址分为行地址和列地址后,可以分别使用两个译码器。

当 \(n\) 为偶数并平均划分时,译码器输出线总数由 \(2^n\) 减少为:

\[ 2\times2^{n/2} \]

减少的输出线数量为:

\[ \boxed{2^n-2\times2^{n/2}} \]

当 \(n\) 为奇数时,行、列地址位数通常分别取 \(\lfloor n/2\rfloor\) 和 \(\lceil n/2\rceil\)。

4、边界对齐与端序🧀

数据按自然边界对齐时,一个 \(N\) 字节对象的起始地址通常是 \(N\) 的整数倍。对齐可能引入填充字节,但能减少跨存储字或跨总线传输的访问。

  • 小端:低有效字节放在低地址。
  • 大端:高有效字节放在低地址。
结构体对齐与小端存储
1
2
3
4
5
struct Record {
    int   a;   // 4 B
    char  b;   // 1 B
    short c;   // 2 B
} record;

假设首地址为 0xC008,各类型按自然边界对齐,record.a = 273,机器采用小端方式。

\[ 273=0x00000111 \]

因此 a 在内存中排列为:

地址 内容
C008 11
C009 01
C00A 00
C00B 00

b 位于 C00C。为了让 2 B 的 short 从偶数地址开始,C00D 是填充字节,c 从 C00E 开始。

Warning

不要机械地记“某种类型后固定空几个字节”。填充量由当前地址、下一成员的对齐要求以及具体 ABI 共同决定。


三、半导体存储器🧀

1、SRAM 与 DRAM🧀

对比 SRAM DRAM
中文 静态随机存取存储器 动态随机存取存储器
存储单元 双稳态触发器,常见为 6T 1 个晶体管和 1 个电容
是否刷新 不需要 需要周期刷新
读出是否破坏 非破坏性 通常为破坏性读出,读后要恢复
速度 快 较慢
集成度 低 高
单位容量成本 高 低
常见用途 Cache 主存

若芯片规格为 \(N\times M\) 位:

  • 存储单元数为 \(N\),数据宽度为 \(M\) 位。
  • 非复用地址需要 \(\lceil\log_2N\rceil\) 根地址线。
  • 需要 \(M\) 根数据线。
  • 完整引脚数还应按题意加入片选、读写控制、电源和地等引脚。

2、DRAM 地址复用与刷新🧀

DRAM 通常把地址分成行地址和列地址,复用同一组地址引脚:先由 RAS 锁存行地址,再由 CAS 锁存列地址。

若 \(N\) 个单元恰好排列为近似方阵,复用后的地址引脚数约为:

\[ \left\lceil\frac{\log_2N}{2}\right\rceil \]

再加上 \(M\) 根数据线以及 RAS、CAS、WE 等控制线。芯片是否另有 CS、OE 等引脚必须以题目给出的接口为准。

DRAM 以行为单位刷新,只需要给出行地址:

刷新方式 做法 特点
集中刷新 在一个时间段连续刷新所有行 刷新期间形成较长“死区”
分散刷新 每个存储周期都安排一次刷新 没有集中死区,但正常访问速度下降
异步刷新 在最大刷新间隔内均匀分配各行刷新 死区短,兼顾访问与刷新
  • 最大刷新间隔:某一行在数据可能丢失前必须再次刷新的最长时间。
  • 刷新周期:系统实际安排完成相邻刷新操作的时间间隔,或者题目定义的一轮刷新时间;不同教材表述略有差异,应结合题意。

在其他条件相同时,行数较少意味着一轮刷新需要的刷新命令较少,但阵列组织还受芯片面积、速度和接口设计制约,不能简单认为“行越少一定越好”。

3、SDRAM🧀

SDRAM 使用时钟与存储器总线同步工作,并支持突发传输。同步接口简化了控制时序,突发传输则适合连续访问一行中的多个数据。

4、ROM 与 Flash🧀

类型 特点
Mask ROM 出厂时写入,不能由用户修改
PROM 用户可编程一次
EPROM 可用紫外线擦除后重新编程
EEPROM 可电擦除,通常支持较细粒度改写
Flash 以块为单位擦除,密度高,广泛用于 SSD 和嵌入式存储

Flash 读取通常较快,但写入前可能需要擦除整个块,因此写入和擦除明显慢于读取,并且擦写次数有限。


四、存储芯片扩展🧀

设单片芯片规格为 \(N\times M\) 位,目标存储器规格为 \(N_t\times M_t\) 位。若二者能够整除,需要的芯片数为:

\[ \boxed{\frac{N_t}{N}\times\frac{M_t}{M}} \]

计算时可以先把所有容量统一换算为 bit,避免混淆 B 和 bit。

1、位扩展🧀

位扩展解决“每个存储字太窄”的问题:

  • 各芯片地址线并联。
  • 各芯片控制线并联。
  • 多片芯片同时工作,每片负责数据总线中的不同位。

例如,把 \(256K\times8\) 扩展为 \(256K\times32\),需要 \(32/8=4\) 片并行工作。

2、字扩展🧀

字扩展解决“存储字数量不足”的问题:

  • 低位地址连接到所有芯片,用于片内寻址。
  • 高位地址经过译码器产生片选信号。
  • 同一时刻通常只选中一个芯片组。
  • 各组共用数据总线。

例如,把 \(256K\times8\) 扩展为 \(2M\times8\),需要 \(2M/256K=8\) 片。

3、字位同时扩展🧀

当存储字数量和数据宽度都不足时,先按位组成一组,再用多个组进行字扩展。

计算 ROM 和 RAM 芯片数

某主存容量为 \(64\,\text{KB}\),其中 ROM 区为 \(4\,\text{KB}\),其余为 RAM,按字节编址。使用 \(2K\times8\) 位 ROM 和 \(4K\times4\) 位 RAM。

ROM 单片容量为:

\[ 2K\times8\,\text{bit}=2\,\text{KB} \]

因此 ROM 需要:

\[ 4\,\text{KB}/2\,\text{KB}=\boxed{2\text{ 片}} \]

RAM 总容量为 \(60\,\text{KB}\)。两片 \(4K\times4\) 先做位扩展,得到一组 \(4K\times8=4\,\text{KB}\);再用 15 组进行字扩展:

\[ 15\times2=\boxed{30\text{ 片}} \]
判断芯片地址范围

用 \(2K\times4\) 位芯片组成 \(8K\times8\) 位存储器。每两个芯片先组成一个 \(2K\times8\) 位组,再用四组扩展字数。

每组覆盖 \(2K=0x800\) 个地址,因此各组起始地址为 0000H、0800H、1000H、1800H。

地址 0B1FH 位于 0800H~0FFFH,所以同时被选中的两片芯片的最小地址均为:

\[ \left\lfloor\frac{0B1F_H}{0800_H}\right\rfloor\times0800_H=\boxed{0800_H} \]

五、Cache🧀

1、基本原理🧀

Cache 位于 CPU 与主存之间,通常由 SRAM 构成。主存和 Cache 都被划分为大小相同的块,数据在二者之间以块为单位调入和换出。

  • 时间局部性:刚访问过的数据很可能再次访问。
  • 空间局部性:某地址附近的数据很可能很快被访问。

访问地址时,Cache 用地址中的 Tag 判断目标主存块是否已经保存在候选行中;命中则直接返回数据,未命中则从下一级存储器调入整个块。

2、性能指标🧀

设 Cache 命中时间为 \(t_c\),未命中后访问主存并调入数据的额外时间为 \(t_m\),命中率为 \(h\):

\[ \boxed{t_a=h t_c+(1-h)(t_c+t_m)=t_c+(1-h)t_m} \]

缺失率为 \(1-h\)。若题目把 \(t_m\) 定义为“未命中时的完整访问时间”而不是额外罚时,则应按题目定义重新列式,不能直接套用上式。

若题目把 Cache 的命中时间作为理想访问时间,可用下式表示简化访问效率:

\[ \boxed{e=\frac{t_c}{t_a}} \]

3、地址划分🧀

设主存地址共 \(m\) 位,按字节编址,每块为 \(2^b\) B,因此块内偏移占 \(b\) 位。

(1)直接映射🧀

主存中的每个块只能放入唯一的一行:

\[ \boxed{\text{Cache 行号}=\text{主存块号}\bmod\text{Cache 行数}} \]

若 Cache 有 \(2^r\) 行:

| Tag(m-r-b 位) | Index(r 位) | Offset(b 位) |

每次只比较一个候选行的标记,硬件简单,但多个主存块映射到同一行时容易产生冲突缺失。

(2)全相联映射🧀

主存中的任意块可以放入 Cache 的任意一行:

| Tag(m-b 位) | Offset(b 位) |

需要同时比较所有 Cache 行的标记,冲突少但硬件成本高。

(3)组相联映射🧀

Cache 先分为若干组,主存块只能进入唯一的一组,但可以放入组内任意一路:

\[ \boxed{\text{组号}=\text{主存块号}\bmod\text{组数}} \]

若 Cache 共 \(2^r\) 行、每组有 \(k\) 路,则组数为 \(2^r/k=2^s\):

| Tag(m-s-b 位) | Set Index(s 位) | Offset(b 位) |

每组需要 \(k\) 个标记比较器,比较器宽度为 Tag 位数。直接映射可视为 1 路组相联,全相联可视为只有 1 组。

4、直接映射例题🧀

已知:

  • 主存地址 32 位,按字节编址。
  • Cache 数据区为 \(32\,\text{KB}\)。
  • 块大小为 \(32\,\text{B}\)。
  • 采用直接映射和写回策略。

Cache 行数为:

\[ \frac{32\,\text{KB}}{32\,\text{B}}=\frac{2^{15}}{2^5}=2^{10} \]

所以 Index 为 10 位,Offset 为 5 位,Tag 为:

\[ 32-10-5=\boxed{17\text{ 位}} \]

每行数据区为:

\[ 32\,\text{B}=256\,\text{bit} \]

加上 17 位 Tag、1 位有效位和写回策略所需的 1 位脏位,每行至少需要:

\[ 256+17+1+1=\boxed{275\,\text{bit}} \]

Tip

Cache 标称容量通常只计算数据区,不包含 Tag、有效位、脏位和替换状态位。题目若问“总容量”或“实际位数”,才需要把这些额外位加入。

若机器字长为 32 bit,则一个字是 4 B;主存块包含 4 个字时,块大小是 \(4\times4=16\) B,而不是 4 B。

5、替换算法🧀

直接映射只有唯一候选行,不需要替换算法;组相联和全相联在候选位置已满时需要选择牺牲块。

算法 选择方式 注意点
RAND 随机选择 硬件简单,结果不稳定
FIFO 替换最早进入的块 不考虑近期是否频繁访问
LRU 替换最长时间未被访问的块 符合时间局部性,路数高时实现成本大
LFU 替换访问次数最少的块 旧数据可能因历史计数过大长期不被换出,常配合衰减机制

对于 \(k\) 路组相联,单个年龄计数器可能需要 \(\lceil\log_2k\rceil\) 位,但精确 LRU 的全部状态不能简单概括为整个组只需 \(\log_2k\) 位。2 路组相联只需 1 位指出最近使用的一路;更高路数常采用近似 LRU。

6、写策略🧀

写命中时:

策略 做法 特点
写回 Write Back 只修改 Cache,块被替换时才写回主存 写主存次数少,需要脏位
写穿 Write Through 同时修改 Cache 和主存 一致性简单,写流量大,常配合写缓冲

写不命中时:

策略 做法
写分配 Write Allocate 先把目标块调入 Cache,再在 Cache 中写入
非写分配 No Write Allocate 不调入 Cache,直接写下一级存储器

常见组合是“写回 + 写分配”和“写穿 + 非写分配”,但这不是强制规则,仍应以具体系统或题目为准。