18 KiB
第4章 存储器
📖 本章介绍存储器的分类、工作原理和层次结构,是课程的重点和难点。 🎯 重点理解存储层次、主存组成、Cache和虚拟存储器
📋 本章目录
4.1 概述
4.1.1 存储器分类
graph TB
A[存储器分类] --> B[按存储介质]
A --> C[按存取方式]
A --> D[按作用]
B --> B1[半导体存储器]
B --> B2[磁表面存储器]
B --> B3[光盘存储器]
C --> C1[随机存储器RAM]
C --> C2[只读存储器ROM]
C --> C3[串行访问存储器]
D --> D1[主存储器]
D --> D2[辅助存储器]
D --> D3[缓冲存储器Cache]
按存储介质分类
| 类型 | 特点 | 示例 |
|---|---|---|
| 半导体存储器 | 体积小、功耗低、速度快、易失性 | SRAM、DRAM |
| 磁表面存储器 | 非易失、容量大、速度慢 | 磁盘、磁带 |
| 光盘存储器 | 非易失、容量大、可移动 | CD、DVD |
按存取方式分类
| 类型 | 特点 | 应用 |
|---|---|---|
| RAM | 随机读写、存取时间与位置无关 | 主存 |
| ROM | 只读不写(或受限写入) | 固件、BIOS |
| 顺序存取 | 按物理顺序寻找(如磁带) | 磁带 |
| 直接存取 | 先直接定位区域,再顺序寻找(如磁盘) | 磁盘 |
RAM和ROM的细分
graph LR
RAM[随机存储器RAM] --> SRAM[静态RAM<br/>触发器原理]
RAM --> DRAM[动态RAM<br/>电容充放电]
ROM[只读存储器ROM] --> MROM[掩模ROM]
ROM --> PROM[可编程ROM]
ROM --> EPROM[可擦除PROM]
ROM --> EEPROM[电擦除PROM]
ROM --> Flash[闪速存储器]
4.1.2 存储器的层次结构
[!important] 核心问题 速度、容量、价格三者不可兼得,需要通过层次结构解决矛盾。
存储器性能指标关系
graph TB
subgraph "存储器层次结构"
REG["寄存器<br/>速度最快、容量最小、价格最高"] --> CACHE["Cache<br/>高速缓冲存储器"]
CACHE --> MEM["主存储器<br/>主存"]
MEM --> DISK["磁盘<br/>辅助存储器"]
DISK --> TAPE["磁带<br/>辅助存储器"]
end
style REG fill:#ff9999
style CACHE fill:#ffcc99
style MEM fill:#ffff99
style DISK fill:#99ff99
style TAPE fill:#9999ff
| 层次 | 速度 | 容量 | 价格 | 位置 |
|---|---|---|---|---|
| 寄存器 | 最快 | 最小 | 最高 | CPU内部 |
| Cache | 很快 | 小 | 高 | CPU内部/外部 |
| 主存 | 较快 | 中等 | 中等 | 主板 |
| 磁盘 | 慢 | 大 | 低 | 外部设备 |
| 磁带 | 最慢 | 最大 | 最低 | 外部设备 |
两个存储层次
graph TB
subgraph "缓存-主存层次"
CPU1[CPU] <--> |"速度接近Cache"| CACHE[Cache]
CACHE <--> |"容量接近主存"| MEM1[主存]
end
subgraph "主存-辅存层次"
MEM2[主存] <--> |"速度接近主存"| DISK[辅存]
CPU2[CPU] -.-> |"不直接访问"| DISK
end
style CPU1 fill:#ff9999
style CPU2 fill:#ff9999
style CACHE fill:#ffcc99
style MEM1 fill:#ffff99
style MEM2 fill:#ffff99
style DISK fill:#99ff99
缓存-主存层次:
- 解决CPU和主存速度不匹配问题
- 数据调动由硬件自动完成
- 对程序员透明
主存-辅存层次:
- 解决存储系统容量问题
- 数据调动由硬件+操作系统完成
- 对程序员透明
4.2 主存储器
4.2.1 主存的基本组成
graph TB
subgraph "主存结构"
MAR[MAR<br/>地址寄存器] --> |"地址"| DEC[译码器]
DEC --> |"选择信号"| MEM[存储体]
MEM <--> |"数据"| MDR[MDR<br/>数据寄存器]
MDR <--> |"数据"| DBUS[数据总线]
MAR <--> |"地址"| ABUS[地址总线]
CTRL[控制电路] --> |"读写控制"| MEM
end
style MAR fill:#ff9999
style MDR fill:#99ccff
style MEM fill:#99ff99
style DEC fill:#ffcc99
工作过程:
- 读操作:CPU将地址送MAR → 地址总线 → 译码器选中单元 → 读出数据到MDR → 数据总线
- 写操作:CPU将地址送MAR,数据送MDR → 发写命令 → 数据写入选中单元
4.2.2 主存中存储单元地址的分配
字节寻址与字寻址
graph TB
subgraph "IBM 370(32位字长)"
A1["地址0"] --> B1["字节0"]
A2["地址1"] --> B2["字节1"]
A3["地址2"] --> B3["字节2"]
A4["地址3"] --> B4["字节3"]
A5["地址4(字地址)"] --> B5["下一个字"]
end
subgraph "PDP-11(16位字长)"
C1["地址0(字地址)"] --> D1["字节0"]
C2["地址1"] --> D2["字节1"]
C3["地址2(字地址)"] --> D3["下一个字"]
end
[!note] 地址表示
- IBM 370:字地址 = 高位字节地址(4的倍数)
- PDP-11:字地址 = 低位字节地址(2的倍数)
4.2.3 主存的技术指标
1. 存储容量
存储容量 = 存储单元个数 \times 存储字长
字节表示:
存储容量 = 存储单元个数 \times 存储字长 / 8
[!example] 示例 24位地址线,按字节寻址:
- 寻址范围:
2^{24} = 16M个字节- 若字长32位:按字寻址范围 =
16M / 4 = 4M个字
2. 存储速度
| 指标 | 定义 | 关系 |
|---|---|---|
| 存取时间 | 启动一次操作到完成的时间 | 读出时间或写入时间 |
| 存取周期 | 连续两次操作的最小间隔 | 存取周期 > 存取时间 |
| 存储器带宽 | 单位时间存取信息量 | 带宽 = 存储字长 / 存取周期 |
提高带宽的措施:
- 缩短存取周期
- 增加存储字长
- 增加存储体
4.2.4 半导体存储芯片
芯片基本结构
graph LR
subgraph "存储芯片"
ADDR[地址线] --> DEC[译码驱动]
DEC --> MEM[存储矩阵]
MEM <--> RW[读/写电路]
RW <--> DATA[数据线]
CS[片选线] --> DEC
RW_CTRL[读写控制线] --> RW
end
容量计算:
芯片容量 = 2^{地址线位数} \times 数据线位数
[!example] 示例
- 10根地址线,4根数据线:
2^{10} \times 4 = 4K位- 14根地址线,1根数据线:
2^{14} \times 1 = 16K位
译码驱动方式
| 方式 | 特点 | 适用场景 |
|---|---|---|
| 线选法 | 一根字线直接选中一个单元 | 容量小的芯片 |
| 重合法 | X、Y两个方向译码,交叉点选中 | 大容量芯片 |
graph TB
subgraph "线选法(16×1字节)"
A1["A3A2A1A0 = 1111"] --> B1["第15根字线选中"]
B1 --> C1["8位数据读出"]
end
subgraph "重合法(1K×1位)"
A2["地址译码"] --> B2["X方向32根线"]
A2 --> C2["Y方向32根线"]
B2 --> D2["交叉点选中1位"]
C2 --> D2
end
4.2.5 随机存取存储器(RAM)
静态RAM(SRAM)
基本单元电路:6个MOS管组成的触发器
特点:
- 用触发器原理寄存信息
- 速度快,不需要刷新
- 集成度低,功耗大
- 用于Cache
典型芯片:Intel 2114(1K×4位)
动态RAM(DRAM)
基本单元电路:1个MOS管 + 电容
特点:
- 用电容充放电原理寄存信息
- 需要定期刷新
- 集成度高,功耗小
- 用于主存
典型芯片:Intel 4116(16K×1位)
刷新方式:
| 方式 | 特点 | 效率 |
|---|---|---|
| 集中刷新 | 一段时间集中刷新所有行 | 有死区 |
| 分散刷新 | 每行刷新分散到各周期 | 无死区,效率低 |
| 异步刷新 | 各行刷新均匀分散 | 折中方案 |
SRAM vs DRAM 对比
| 特性 | SRAM | DRAM |
|---|---|---|
| 存储原理 | 触发器 | 电容 |
| 速度 | 快 | 较慢 |
| 集成度 | 低 | 高 |
| 功耗 | 大 | 小 |
| 刷新 | 不需要 | 需要 |
| 价格 | 高 | 低 |
| 应用 | Cache | 主存 |
4.2.6 只读存储器(ROM)
| 类型 | 特点 | 应用 |
|---|---|---|
| MROM | 厂家掩模制作,不可更改 | 批量生产 |
| PROM | 用户可编程一次 | 小批量 |
| EPROM | 紫外线擦除,可重复编程 | 开发调试 |
| EEPROM | 电擦除,可重复编程 | 参数存储 |
| Flash | 电擦除,速度快 | U盘、SSD |
4.2.7 存储器与CPU的连接
存储器容量扩展
三种扩展方式:
graph TB
subgraph "位扩展"
A1["芯片1(8位)"] --> C1["组合(16位)"]
A2["芯片2(8位)"] --> C1
end
subgraph "字扩展"
B1["芯片1(1K×8)"] --> D1["组合(2K×8)"]
B2["芯片2(1K×8)"] --> D1
end
subgraph "字位同时扩展"
E1["芯片1"] --> F1["组合"]
E2["芯片2"] --> F1
E3["芯片3"] --> F1
E4["芯片4"] --> F1
end
| 扩展方式 | 连接方法 | 应用场景 |
|---|---|---|
| 位扩展 | 地址线、控制线并联,数据线串联 | 增加字长 |
| 字扩展 | 地址线、数据线、控制线并联,片选线用高位地址 | 增加字数 |
| 字位扩展 | 先位扩展,再字扩展 | 大容量存储器 |
存储器与CPU连接示例
graph TB
subgraph "CPU"
MAR[MAR] --> |"地址"| ADDR[地址总线]
MDR[MDR] <--> |"数据"| DATA[数据总线]
CTRL[控制信号] --> |"读写"| RW[读写控制]
end
subgraph "存储器"
ADDR --> |"地址"| CHIP1[芯片1]
ADDR --> |"地址"| CHIP2[芯片2]
CHIP1 <--> |"数据"| DATA
CHIP2 <--> |"数据"| DATA
CS1[片选1] --> CHIP1
CS2[片选2] --> CHIP2
RW --> CHIP1
RW --> CHIP2
end
4.2.8 存储器的校验
奇偶校验
原理:增加1位校验位,使数据中1的个数为奇数(奇校验)或偶数(偶校验)。
特点:
- 简单,只能检测奇数位错误
- 不能纠错
海明码(Hamming Code)
原理:在数据位中插入多个校验位,通过校验位的组合定位错误位。
校验位数r满足:$2^r \geq m + r + 1$(m为数据位数)
特点:
- 可以检测并纠正1位错误
- 可以检测2位错误
[!example] 示例 8位数据需要4位校验码:
- 总位数:8 + 4 = 12位
- 校验位位置:1, 2, 4, 8
- 可纠正1位错误
4.3 高速缓冲存储器(Cache)
4.3.1 Cache的基本原理
[!important] 为什么需要Cache CPU速度远快于主存,Cache作为中间缓冲,解决速度不匹配问题。
graph LR
CPU[CPU] <--> |"速度匹配"| CACHE[Cache]
CACHE <--> |"容量大"| MEM[主存]
style CPU fill:#ff9999
style CACHE fill:#ffcc99
style MEM fill:#99ff99
工作原理:
- CPU访问数据时,先查Cache
- 命中:直接从Cache读取(快)
- 未命中:从主存读取,同时调入Cache
4.3.2 Cache命中率
命中率:
H = \frac{N_c}{N_c + N_m}
- $N_c$:Cache访问次数
- $N_m$:主存访问次数
平均访问时间:
T_a = HT_c + (1-H)T_m
访问效率:
e = \frac{T_c}{T_a} = \frac{1}{H + (1-H)r}
其中 $r = T_m / T_c$(主存与Cache访问时间之比)
[!example] 示例 Cache命中率95%,Cache访问时间10ns,主存访问时间100ns:
T_a = 0.95 \times 10 + 0.05 \times 100 = 14.5nse = \frac{10}{14.5} = 69\%
4.3.3 Cache地址映射
[!info] 问题 主存块如何放入Cache?需要地址映射。
三种映射方式
1. 直接映射(Direct Mapping)
规则:每个主存块只能映射到Cache的固定行。
映射公式:i = j \mod m
- i:Cache行号
- j:主存块号
- m:Cache行数
graph LR
subgraph "直接映射"
M0[主存块0] --> C0[Cache行0]
M1[主存块1] --> C1[Cache行1]
Mm[主存块m] --> Cm[Cache行m]
Mm1[主存块m+1] --> C0
end
地址结构:
| 标记(Tag) | Cache行号(Index) | 块内地址(Offset) |
|---|
优点:实现简单,查找速度快 缺点:灵活性差,命中率低
2. 全相联映射(Fully Associative Mapping)
规则:主存块可以映射到Cache的任意行。
graph LR
subgraph "全相联映射"
M0[主存块0] --> |"任意行"| CACHE[Cache]
M1[主存块1] --> |"任意行"| CACHE
Mn[主存块n] --> |"任意行"| CACHE
end
地址结构:
| 标记(Tag) | 块内地址(Offset) |
|---|
优点:灵活性好,命中率高 缺点:查找速度慢,硬件成本高
3. 组相联映射(Set Associative Mapping)
规则:将Cache分组,主存块映射到固定组,组内任意行。
映射公式:q = j \mod u
- q:Cache组号
- j:主存块号
- u:Cache组数
graph LR
subgraph "组相联映射"
M0[主存块0] --> G0[Cache组0]
M1[主存块1] --> G1[Cache组1]
Mu[主存块u] --> Gu[Cache组u]
Mu1[主存块u+1] --> G0
end
地址结构:
| 标记(Tag) | 组号(Index) | 块内地址(Offset) |
|---|
优点:折中方案,兼顾速度和命中率 应用:现代Cache常用2路、4路、8路组相联
三种映射方式对比
| 方式 | 映射规则 | 灵活性 | 命中率 | 硬件复杂度 |
|---|---|---|---|---|
| 直接映射 | 固定行 | 差 | 低 | 简单 |
| 全相联映射 | 任意行 | 好 | 高 | 复杂 |
| 组相联映射 | 固定组,任意行 | 中 | 中 | 中等 |
4.3.4 Cache替换算法
[!info] 问题 Cache满时,新块调入需要替换旧块,如何选择?
常用替换算法
| 算法 | 原则 | 优点 | 缺点 |
|---|---|---|---|
| FIFO | 先进先出 | 实现简单 | 不考虑访问频率 |
| LRU | 最近最少使用 | 命中率高 | 实现复杂 |
| LFU | 最不经常使用 | 考虑频率 | 需要计数器 |
| 随机替换 | 随机选择 | 实现简单 | 命中率不稳定 |
LRU算法实现:
- 为每行设置计数器
- 每次访问,命中行计数器清零,其他行加1
- 替换计数器值最大的行
4.3.5 Cache写策略
[!info] 问题 Cache数据修改后,如何与主存保持一致?
写策略
| 策略 | 方法 | 优点 | 缺点 |
|---|---|---|---|
| 写直达 | 同时写Cache和主存 | 数据一致性好 | 速度慢 |
| 写回法 | 只写Cache,替换时写回主存 | 速度快 | 数据可能不一致 |
graph TB
subgraph "写直达"
CPU1[CPU] --> |"写"| CACHE1[Cache]
CPU1 --> |"同时写"| MEM1[主存]
end
subgraph "写回法"
CPU2[CPU] --> |"写"| CACHE2[Cache]
CACHE2 --> |"替换时写回"| MEM2[主存]
end
4.3.6 Cache性能分析
加速比:
加速比 = \frac{T_m}{T_a} = \frac{r}{1 + (r-1)H}
Cache容量选择:
- 太小:命中率低
- 太大:成本高,速度可能下降
- 通常:几十KB到几MB
4.4 虚拟存储器
4.4.1 虚拟存储器的概念
[!info] 定义 虚拟存储器是一个逻辑模型,程序员看到的地址空间远大于实际主存。
特点:
- 虚拟地址(逻辑地址):程序员使用的地址
- 物理地址(实地址):主存实际地址
- 地址转换由硬件和OS自动完成
graph TB
subgraph "虚拟存储器"
VA[虚拟地址空间<br/>很大] --> |"地址转换"| PA[物理地址空间<br/>较小]
PA --> MEM[主存]
MEM --> DISK[辅存]
end
4.4.2 页式虚拟存储器
基本思想:
- 虚拟地址空间划分为固定大小的页
- 主存划分为相同大小的页框
- 通过页表建立映射关系
地址结构:
| 虚页号 | 页内地址 |
|---|
页表项:
| 虚页号 | 实页号 | 有效位 | 修改位 |
|---|
地址转换过程:
- 从虚拟地址取出虚页号
- 查页表得到实页号
- 实页号 + 页内地址 = 物理地址
4.4.3 TLB(快表)
[!info] 问题 页表在主存中,每次访问都要查页表,速度慢。
解决方案:在CPU中设置TLB(Translation Lookaside Buffer)
特点:
- 高速小容量存储器
- 存放最近使用的页表项
- 命中率通常 > 99%
访问流程:
- 先查TLB
- TLB命中:直接得到物理地址(快)
- TLB未命中:查页表,更新TLB
📝 本章小结
核心概念
- 存储层次:寄存器 → Cache → 主存 → 辅存
- 主存组成:存储体 + MAR + MDR + 译码驱动 + 读写电路
- RAM分类:SRAM(快,用于Cache)、DRAM(慢,用于主存)
- Cache映射:直接映射、全相联映射、组相联映射
- 虚拟存储器:虚拟地址 → 物理地址的转换
关键公式
- 存储容量 = 存储单元个数 × 存储字长
- Cache命中率
H = N_c / (N_c + N_m) - 平均访问时间
T_a = HT_c + (1-H)T_m - 访问效率
e = T_c / T_a
重点图示
[!summary] 必须掌握的图
- 存储器层次结构图
- 主存基本组成框图
- Cache三种映射方式示意图
- Cache访问流程图
🧪 自测练习
概念题
- 说明存储器层次结构的必要性。
- 比较SRAM和DRAM的特点。
- 解释Cache三种映射方式的区别。
计算题
- 某系统Cache命中率90%,Cache访问时间20ns,主存访问时间200ns,求平均访问时间和访问效率。
- 24位地址线,按字节寻址,存储字长32位,求存储容量。
分析题
- 设计一个16K×8位的存储器,使用4K×4位的芯片。
- 说明Cache写策略的选择依据。
🔗 相关链接
- 03_系统总线 - 上一章
- 05_输入输出系统 - 下一章
- 08_CPU结构与功能 - CPU访问存储器
- 06_运算方法 - 数据表示
本章难度:⭐⭐⭐⭐⭐ 困难 重要程度:⭐⭐⭐⭐⭐ 核心重点