--- title: "03-存储系统" created: 2026-08-29 tags: - 基础与理论 - 计算机组成原理 - "408" --- # 03 存储系统 > 📚 本文是 [[00-计算机组成原理总览|计算机组成原理]] 的第 3 篇,相关系列见 [[00-基础与理论|基础与理论]]。 存储系统是计组的心脏章节——**Cache 的三映射、LRU、写策略**是全 408 考频最高的知识点之一。整章围绕一个矛盾展开:**又快又大的存储器不存在**(SRAM 快但贵、DRAM 便宜但慢),于是工程师用**金字塔**把它们摞起来用。 ## 一、存储金字塔与局部性 ``` 寄存器 最快(<1ns) 最贵 ┐ L1 Cache ~1ns │ 容量小、速度快 L2/L3 Cache ~4-40ns │ CPU 内/旁边 主存 DRAM ~100ns ┘ SSD/磁盘 ~100μs / ~10ms 磁带/云归档 慢且便宜 ``` 撑起金字塔的是**局部性原理**([[01-计算机硬件速览|硬件速览]]埋过伏笔): - **时间局部性**:刚访问过的东西,很快会再访问(循环、热点变量) - **空间局部性**:访问某地址后,附近的地址大概率被访问(数组遍历、顺序取指) 💡 Cache 的全部逻辑就是一句:**用局部性"赌"你下次要的数据我已经提前搬到楼上了**。赌对(命中)就是天价速度,赌错(缺失)就要下楼下一次。 ### 分类速记 | 分类角度 | 类别 | |---|---| | 按介质 | 半导体(主存/Cache)、磁表面(磁盘)、光介质 | | 按可改写 | RAM(随机读写)/ ROM(只读为主);**易失 vs 非易失**(断电丢不丢) | | 按访问方式 | 随机存取(内存)、顺序存取(磁带)、直接存取(磁盘:先定位磁道再顺序) | ⚠️ 磁盘是"**直接存取**"不是"随机存取";CD-ROM 是"**只读**"半导体闪存属于 ROM 家族(Flash=电可擦写 ROM)。 ## 二、主存:SRAM vs DRAM | 维度 | SRAM(静态) | DRAM(动态) | |---|---|---| | 存储原理 | **触发器**(6 个晶体管锁 1 位) | **电容**存电荷(1 管 1 电容) | | 刷新 | 不需要 | **需要定期刷新**(电荷会漏) | | 速度 | 快(1ns 级) | 慢(几十 ns) | | 成本/集成度 | 贵/低 | 便宜/高 | | 用途 | **Cache** | **主存**(内存条)、显存 | DRAM 刷新方式三种(考点): - **集中刷新**:一段时间集中刷,期间死时间(访存"死区") - **分散刷新**:每次读写后顺带刷一行,无死区但系统变慢 - **异步刷新**:折中——隔一小段刷一行,2ms 内每行都刷到,死时间最短(现代 DDR 采用) 💡 **SDRAM → DDR 演化**:SDRAM(同步 DRAM,与时钟同步)→ DDR(Double Data Rate,**时钟上下沿各传一次**)→ DDR2/3/4/5(预取位数翻倍、频率提升)。买内存条的"DDR4-3200"意思就是第 4 代、3200 MT/s(每秒百万次传输)。 ### ROM 家族 MROM(厂家掩膜)→ PROM(一次编程)→ EPROM(紫外线擦)→ EEPROM(电擦,字节级)→ **Flash**(块级电擦:NOR 用于 BIOS/嵌入式,NAND 用于 SSD/U 盘)→ SSD = NAND Flash 阵列 + 控制器(详见 [[09-磁盘与固态硬盘]])。 ⚠️ BIOS 芯片是 Flash(历史上是 EPROM)——所以"BIOS 是 ROM"这句话在现代语境下要说成"BIOS 固件存在 Flash 芯片里"。 ## 三、主存容量扩展与编址 ### 1. 位扩展(加大"宽度") 1 片 8K×1 位的芯片不够宽?**8 片并联**拼成 8K×8 位——地址线共用、数据线各出一位。 ### 2. 字扩展(加大"深度") 1 片 8K×8 位不够深?**4 片轮流上**拼成 32K×8 位——用高位地址(2 位)经译码器选片,低位地址片内寻址。 ### 3. 字位同时扩展 总片数 = (总容量/单片容量) 完整套路:**位扩展定"每组几片",字扩展定"共几组"**。 💡 例:用 16K×4 位芯片组成 64K×8 位存储器 → 位方向 8/4=**2 片/组**,字方向 64K/16K=**4 组** → 共 **8 片**;需片选译码的地址线数 = log₂4 = 2 根。 ### 4. 交叉编址(多体并行) 低位交叉编址:连续地址**轮流分布**在不同存储体——正好吃掉空间局部性,流水式访问。 - 设总线传送周期 τ、存储周期 T(T > τ),m 体低位交叉流水读取 m 个字: $$t = T + (m-1)\tau$$ 💡 例:4 体交叉,T=8τ → 连续读 4 个字耗时 8τ + 3τ = **11τ**(顺序编址则要 4T = 32τ)。 ⚠️ 高位交叉是"每体连续编址"(扩展容量用),**低位交叉才能提速**——别混。 ## 四、Cache 映射:三选一的坐标问题 主存块往 Cache 里放,核心问题是"**放哪、怎么找到**"。设 Cache 共 2ᶜ 块,每块 2ᵇ 字节,主存地址共 n 位。 ### 1. 直接映射:一块只有唯一座位 主存第 j 块 → Cache 第 (j mod 2ᶜ) 号行。 地址划分(从高到低):**标记 tag | Cache 行号 c 位 | 块内偏移 b 位** - 优点:硬件最简单,查找一次就定位 - 缺点:冲突率高——第 0 块和第 2ᶜ 块抢同一个座位 ### 2. 全相联:随便坐 任何块可放 Cache 任意行。地址划分:**标记 tag(n−b 位)| 块内偏移 b 位** - 优点:最灵活,冲突最低 - 缺点:要和**所有行的标记并行比较**(相联存储器),硬件贵——只适合小容量(TLB 用它) ### 3. 组相联:分组内随便坐(折中赢家) Cache 分 2^q 组,每组 2^r 块(r 路)。主存第 j 块 → 第 (j mod 2^q) 组,组内随便放。 地址划分:**标记 tag | 组号 q 位 | 块内偏移 b 位** - r=1 退化为直接映射;r=组数(单组)退化为全相联 - 现代 CPU 的 L1 一般 8 路、L2/L3 更高路数 ### 手算例题(408 真题风格) 主存 4GB(32 位地址)、按字节编址,Cache 数据容量 64KB、块大小 16B、4 路组相联: - 块内偏移:16B = 2⁴ → **b=4** - Cache 行数:64KB/16B = 4096 行;4 路 → 4096/4 = 1024 组 → **q=10** - 标记:32 − 10 − 4 = **18 位** - 访问地址 0x12345678:组号 = (0x12345678 >> 4) & 0x3FF,标记 = 高 18 位——命中比较只在这 1 组的 4 行里进行 ⚠️ 地址划分从**低位往高位**切:先偏移、再组号、剩下全给标记。直接映射则中间是行号。**"组号/行号取中间"是铁律**——偏移必须在最低位。 ## 五、替换算法与写策略 ### 1. 替换算法(直接映射不需要——座位唯一) | 算法 | 做法 | 特点 | |---|---|---| | RAND | 随机换 | 实现最简单,命中率不稳定 | | FIFO | 先进先出 | 可能淘汰"最老但最热"的块 | | **LRU** | 最久**未**被访问的先换 | 408 必考手算;硬件用计数器实现 | | LFU | 访问次数最少 | 统计成本高,可能误伤新块 | **LRU 手算例题**:Cache 3 块,访问序列 **1, 2, 3, 1, 4, 1, 2, 5**: | 访问 | 1 | 2 | 3 | 1 | 4 | 1 | 2 | 5 | |---|---|---|---|---|---|---|---|---| | Cache 状态 | [1] | [2,1] | [3,2,1] | [1,3,2] | **淘汰2**→[4,1,3] | [1,4,3] | **淘汰3**→[2,1,4] | **淘汰4**→[5,2,1] | 逐步逻辑:每次访问把该块提到"最新";满了之后,**最久没碰的**(从最新往里数排最后的)被换出。命中 3 次(1、1、2),缺失 5 次,命中率 3/8。 ### 2. 写命中策略 | 策略 | 写命中时 | 优点 | 缺点 | 需要 | |---|---|---|---|---| | 全写法(写穿透 write-through) | 同时写 Cache **和** 主存 | 主存永远一致 | 每次写都访存,慢 | 写缓冲 | | 回写法(write-back) | 只写 Cache,**标记脏位**;换出时才写回主存 | 写速度快 | 主存暂时"过时" | **脏位** | ⚠️ 考点三连:① 回写法需要**脏位**(dirty bit)判断换出时是否写回;② 写缺失处理分"写分配"(配回写法:把块调上来再写)与"非写分配"(配全写法:直接写主存不调块);③ **多核 Cache 一致性问题**(MESI 协议思想:一个核写了,别的核的副本要失效)——这是回写法的深层代价。 ### 3. Cache 性能算术 - 命中率 h = 命中次数/总访问次数 - 平均访存时间 = h × tc + (1−h) × tm(tc 是 Cache 访问时间,tm 是主存访问时间) - 💡 例:tc=10ns,tm=100ns,h=95% → 0.95×10 + 0.05×100 = 9.5 + 5 = **14.5ns**——比 100ns 快了近 7 倍,全靠局部性把 h 撑高 ## 六、虚拟存储 vs Cache:同一套思想 [[06-内存管理|内存管理]] 讲过:OS 用**页表**把虚拟地址翻译成物理地址,把"大虚拟空间"映射到"小物理内存"。对照一下: | 维度 | Cache | 虚拟存储 | |---|---|---| | 谁管 | **硬件**全自动 | **OS + 硬件**(MMU) | | 缺失代价 | 几十 ns | 缺页 → 磁盘 I/O,百万倍 | | 块大小 | 64B 级 | 4KB 级 | | 映射 | 组相联为主 | 页表(全相联思想:任何页进任何页框) | **TLB(快表)**:页表太大、查一次页表要多访存一次,于是把最热的页表项缓存进 MMU 里的小 SRAM——**它就是"页表的 Cache"**,用全相联(或组相联)。TLB 命中 → 地址翻译 1 次访存搞定;TLB 缺失 → 再查页表。完整流程:**TLB → 页表 → Cache → 主存 → 磁盘**,每一级都是同一套"金字塔 + 局部性"思想。 ⚠️ 408 高频题:给 TLB 命中率、Cache 命中率,算"访问一次数据的平均耗时"——把这条链的时间相加即可,注意"TLB 和 Cache 同时命中最快"这条捷径。 ## 七、盲点自测 1. SRAM 和 DRAM 的存储原理、用途各是什么?(触发器/电容;Cache/主存) 2. 4 体低位交叉编址、T=8τ,读 4 个字要多久?(T+3τ=11τ) 3. 直接映射的地址三段怎么切?(标记|行号|偏移,行号在中,偏移在底) 4. LRU 和 FIFO 的区别用一句话说?(LRU 看"最久未用",FIFO 看"最早进来"——最老的块可能最热) 5. 回写法为什么需要脏位?(区分"改过要写回"与"没改直接扔") 6. TLB 缓存的是什么?它在金字塔的哪一层?(页表项/页框号;MMU 内的 SRAM,比 L1 更小更快) 7. 平均访存时间公式里 (1−h) 为什么直接用 tm 不用 tc+tm?(近似:缺失时数据直接从主存来;严格式为 tc+(1−h)tm,注意题目口径) ## 八、动手玩 ```bash # 看 CPU 的 Cache 结构(macOS) sysctl -a | grep -i cache # hw.l1icachesize / hw.l1dcachesize / hw.l2cachesize / hw.l3cachesize # Linux 更详细 lscpu | grep -i cache # L1d/L1i/L2/L3 的容量与映射关系 ``` 注意输出里 **L1i 和 L1d 是分开的**——这就是 [[01-系统概述]] 里说的"现代 CPU 的 L1 是哈佛结构",为了取指和取数不打架。 ## 参考资料 - 王道《计算机组成原理考研复习指导》第 3 章 - CSAPP 第 6 章《存储器层次结构》——本章的"黄金完整版",六组相联映射讲得最透 - [[01-计算机硬件速览]]——金字塔的感性版;[[06-内存管理]]——虚拟存储的 OS 视角 ⬅️ [[02-数据的表示与运算|数据的表示与运算]] 🏠 [[00-基础与理论|00-基础与理论]] ➡️ [[04-指令系统|指令系统]]