📖 工程现场:飞控软件的「驻留」运行 对安全攸关的机载软件而言,「程序运行期间绝不从慢速介质现场取指令」几乎是铁律:起飞前,飞控程序与关键数据已经完整载入内存并完成校验,飞行全程所需的关键指令都在这台「工作台」上随取随用;外存里的副本只作为加载源与备份。原因正是本节的数字——如果关键运算还要临时等硬盘毫秒级响应,一个颠簸时序就乱套了。工程师甚至会给「哪些东西必须在内存里」列清单逐项核查,这份谨慎,来自对数量级的敬畏。
🎯 本章学习目标
- 理解内存与 CPU 的「速度-容量」分工。
- 掌握 SRAM(触发器)与 DRAM(电容)的物理原理与区别。
- 理解 DRAM 为什么需要「刷新」,以及「易失性」的含义。
- 理解内存寻址:地址如何选中一个存储单元。
9.1内存的角色:CPU 的高速工作台
CPU 每秒要处理几十亿次运算,每次都从硬盘读数据?那会慢到无法忍受——硬盘是毫秒级,CPU 是纳秒级,差了百万倍。所以计算机需要一层「速度贴近 CPU、容量足够放程序和数据」的中间地带,这就是 内存(memory,主存)。
内存是 CPU 的工作台:正在运行的程序、正在处理的数据,都摊在这个台面上,CPU 随手可取。它遵循第 7 章说的「随机访问」——按地址直接读写任意单元。
核心思想:存储金字塔 计算机的存储是一个金字塔:越靠近 CPU 越快、越贵、越小。从快到慢是:寄存器 → 缓存(SRAM)→ 内存(DRAM)→ 硬盘/SSD。内存处在一个「速度与容量折中」的关键位置。
🧠 一句话记忆 内存 = CPU 的工作台,越近越快;它是「快」与「大」之间的折中。
深一层:把「快慢差百万倍」算成看得见的数字
「CPU 是纳秒级、硬盘是毫秒级」这句话,值得用数字砸实。设一颗 3 GHz 的 CPU,一个时钟周期约 0.33 ns。访问一次内存约需 100 ns——CPU 干等约 300 个时钟周期;而等硬盘吐一次数据约需 5 ms,折合约 1500 万个时钟周期。什么概念?在等硬盘的这一会儿,足够这颗 CPU 完整执行上千万条指令。如果每次运算都直连硬盘,CPU 有 99.99% 以上的时间在发呆——这就是「工作台」非有不可的定量理由:内存的存在,就是把「毫秒世界」翻译成「百纳秒世界」,让 CPU 的等待从千万拍降到几百拍。
再往深处问一层:程序到底是怎么「住进」内存的?回想第 7 章——程序平时是文件,安静地躺在硬盘里(外存);双击图标的那一刻,操作系统把它的指令与数据成批搬运进内存,CPU 才开始按 PC 一条条取指执行。内存里因此常驻着两类「住户」:正在运行的程序代码(指令),和程序正在摆弄的数据(变量、数组、缓冲区)。关机即清空——第 12 章讲操作系统时你会看到,内存的每一个字节都被操作系统编了号、分了户,谁也不许越界。
📐 例题 1 没有内存世界会怎样?——访存代价的三个数量级
设 CPU 主频 3 GHz(一个时钟周期约 0.33 ns)。分别计算它访问一次所需等待的时钟周期数:(1) 访问 CPU 内部寄存器(约 0.3 ns,一拍内完成);(2) 访问内存(约 100 ns);(3) 访问机械硬盘(约 5 ms)。并比较三者相差的倍数。
思路 等待的拍数 = 等待时间 ÷ 时钟周期。逐项相除,再两两作比。
解 周期 = 1 ÷ (3×109) ≈ 0.333 ns。
(1) 寄存器:0.3 ÷ 0.333 ≈ 1 拍(就在本拍内完成)。
(2) 内存:100 ÷ 0.333 ≈ 300 拍。
(3) 硬盘:5 ms = 5×106 ns,5×106 ÷ 0.333 ≈ 1500 万拍。
倍数:内存等待是寄存器的约 300 倍;硬盘等待是内存的 5×106 ÷ 100 = 5 万倍,是寄存器的约 1500 万倍。
答:1 拍 / 300 拍 / 1500 万拍;硬盘比内存慢 5 万倍。 ⚠ 易错点:① 毫秒换纳秒要乘 106,不是 103;② 结论要反过来读——正因为每差一层慢百倍以上,「金字塔」每一层都必须存在,少一层 CPU 就得原地空转;③ 「内存 100 ns」是平均口径,DRAM 其实比硬盘快在随机访问:硬盘换个位置要挪磁头(机械动作,毫秒级),内存换地址只是换个行列编号(电子动作,纳秒级)。
辨析:内存大 ≠ 随便用 「内存当工作台」还有个隐含推论:工作台再大,也得「摊得开程序」。程序需要把代码、数据、调用栈同时摊在台上——若内存太小,系统被迫在内存与硬盘之间来回倒腾(术语叫「换页」),每次倒腾都是上面算过的「5 万倍慢」级别的搬运,机器立刻卡成幻灯片。「内存不足导致卡顿」的病根不在内存「不够存」,而在「摊不开 + 倒腾太贵」,这也是第 12 章虚拟内存要解决的问题。
顺带建立一条工程常识:内存坏了,症状往往「没规律」。硬盘坏了多是「特定文件打不开」,而内存是随机访问的公共工作台——某个单元坏了,程序运行到哪个倒霉指令、哪个变量恰好落在这个单元,是随机的:于是表现为「偶尔死机、不定期蓝屏、程序莫名其妙崩溃」,重启又一切正常。诊断方法也就朴素而硬核:用内存测试软件把每个单元写 0、写 1、写交替图案、读回来逐位比对——把几十亿个「储物柜」挨个开箱查一遍。这要跑很久(几小时起步),因为要覆盖所有单元、还要趁刷新与温度变化把问题暴露出来。下次遇到「玄学死机」,先想到的应该是内存——这是装机维修行业排名第一的排查直觉。
9.2SRAM:触发器组成的静态内存
第一种内存 SRAM(Static RAM,静态随机存取存储器),用的正是第 6 章学的触发器。每个存储单元,就是一组交叉耦合的晶体管构成的触发器——只要不断电,它就牢牢锁住当前的 0 或 1,不用任何「维护」。
📖 名词溯源:Static 的「静」 SRAM 里的 Static(静态)指的不是「不工作」,而是数据一旦写入就稳稳保持,不需要周期性「刷新」。它「静」在状态稳定、无需打理。
SRAM 的优点:极快、稳定、无需刷新。缺点也很致命:一个触发器要用4~6 个晶体管才能存 1 个 bit,占用面积大、成本高、功耗大。所以 SRAM 不适合做大容量内存,它用在 CPU 内部的高速 缓存(cache)里——那里容量小、但要最快。
| 特性 | 说明 |
|---|---|
| 存储原理 | 触发器(交叉耦合晶体管) |
| 每个 bit 用晶体管数 | 约 4–6 个 |
| 是否需要刷新 | 不需要 |
| 特点 | 快、稳,但大、贵 |
🧠 一句话记忆 SRAM = 触发器内存,快而稳但贵,所以只用在缓存里。
深一层:交叉耦合——「自己撑住自己」的记忆术
SRAM 单元的核心,是第 6 章那对交叉耦合的反相器:A 的输出接 B 的输入,B 的输出又接回 A 的输入,围成一个首尾相咬的环。不妨设 A 输出 1,B 收到 1 便输出 0,这个 0 馈回 A 又把 A「钉」在 1——两个门互相拉扯又互相成全,状态就这样被自己撑住了。电路里存在两个稳定态(A=1,B=0 与 A=0,B=1),恰对应 1 与 0;想改写,就用外力强行把环拨到另一个稳态,撒手后它就在新态上继续自锁。记忆的本质,是让电路自己咬住自己——这也是「触发器」这个名字的由来:一旦触发翻转,就稳稳锁死在新状态。
为什么 SRAM「快」?因为它读数据时不需要任何「充放电」过程——交叉耦合环上的电平本来就在那儿,字线一开,位线上立刻能感知到它是高是低;写也同理,直接把环拨过去。对比 DRAM 读一位要从电容里「倒出」电荷、还要经历放大与回写(9.3 节详述),SRAM 的读写是「看一眼」「拨一下」的轻松活。工程上经典的 6 管单元,就是 2 个构成环的晶体管加 4 个负责开门与负载的辅助管——一个 bit 六个管,这就是「贵」的物理账单。
📐 例题 2 一本晶体管账:32 MiB 缓存 vs 16 GiB 内存
某 CPU 的三级缓存共 32 MiB(用 SRAM 实现,6 管/bit),某电脑内存 16 GiB(用 DRAM 实现,1 晶体管 + 1 电容/bit)。(1) 缓存与内存各含多少 bit?(2) 各需多少个晶体管?DRAM 还需多少个电容?(3) 同样做 1 GB,SRAM 与 DRAM 的单元数相差几倍?
思路 容量换算:1 MiB = 220 字节,1 GiB = 230 字节,1 字节 = 8 bit。再按每 bit 的单元构成数乘。
解 (1) 缓存:32 × 220 × 8 = 268 435 456 bit(约 2.68 亿);内存:16 × 230 × 8 = 137 438 953 472 bit(约 1374 亿)。
(2) SRAM 需晶体管:2.68 亿 × 6 ≈ 16.1 亿个。DRAM 需晶体管约 1374 亿个,外加同样数目(约 1374 亿个)的微型电容。
(3) 每 GB:SRAM 需 8×230×6 ≈ 51.5 亿个晶体管;DRAM 需 8×230 ≈ 85.9 亿个单元但每单元仅 1 管。同容量下 SRAM 的晶体管数是 DRAM 的 6 倍,再叠加 SRAM 单个晶体管占的面积通常更大,「贵好几倍、容量小几级」便有了着落。
答:缓存 2.68 亿 bit、内存 1374 亿 bit;SRAM 约 16.1 亿管、DRAM 约 1374 亿管 + 1374 亿电容;SRAM 单元成本约为 DRAM 的 6 倍。 ⚠ 易错点:① MiB/GiB 是 2 的幂(1 GiB = 230 B),与硬盘厂商标 GB 的十进制(109)不同口径;② 16 GiB ≈ 17.2 GB(十进制),本题按同口径比较即可;③ 别忘了电容虽不算「晶体管」,同样占面积——DRAM 省的本质是「每 bit 的元件数少」。
顺理成章的工程布局:CPU 把最常用的少量数据放进片内 SRAM 缓存(L1 最快最小、紧贴运算单元;L2 稍大稍慢;L3 最大最慢、供多核心共享),把整个程序放在大容量 DRAM 里——SRAM 出速度,DRAM 出容量,一对搭档各司其职。缓存凭小赌快、内存凭大兜底,而它俩配合的天衣无缝,靠的是本章后面要揭开的「局部性」规律。
辨析:「静态」= 不耗电吗? 不。SRAM 单元不掉电时,交叉耦合环里的晶体管始终有微弱的静态漏电流(栅极与结的泄漏),待机也在慢耗电——「静态」指状态不需要周期性维护,不是零功耗。反过来,DRAM 的耗电大头是「刷新 + 充放电」,动态开销更高。两者的省电策略也不同:SRAM 靠关断电源域「断电丢数据换省电」;DRAM 靠「自刷新模式」——降到一个只维持刷新的极低功耗档位保住数据(9.4 节会讲)。名与实,要分开记。
把 SRAM 的读写动作再分解慢放一遍,体会「开门-感知/拨动-锁门」的节奏:读——行译码器点亮字线,本行所有单元的存取管同时打开,各单元环上的电平涌上各自的位线,读出放大电路比较位线高低判出 0/1;写——同样先开字线,但这次由位线被强行驱动到目标电平(写 1 就拉高、写 0 就拉低),强过环内电流,把交叉耦合环「拨」进新稳态,随后关闭字线,环咬住新值。整个过程全是对已有积木的调用:译码器选路、电平感知识别、正反馈锁存——第 5、6 章的组合与时序电路,在这里合体上岗。
9.3DRAM:电容 + 晶体管的动态内存
要又大又便宜,得换个更「抠」的思路。这就是 DRAM(Dynamic RAM,动态随机存取存储器),你电脑内存条里装的就是它。
DRAM 的存储单元只有一个晶体管 + 一个电容:
- 电容:一个能储存电荷的微型「电罐」。有电荷 = 1,没电荷 = 0。
- 晶体管:当作开关,控制「要不要读/写这个电容」。
这个设计的妙处在于极度省料:一个 bit 只要 1 个晶体管 + 1 个电容,比 SRAM 省好几倍。所以同样面积能塞进多得多的 bit,成本也低得多——这正是内存能做大、做便宜的物理原因。
📖 名词溯源:Dynamic 的「动」 DRAM 里的 Dynamic(动态)来自一个麻烦:电容会漏电。电容存的电荷会慢慢流失,数据「动」了、不稳了。所以它必须不断「刷新」才能保持——这正是「动态」的代价。
🧠 一句话记忆 DRAM = 1 管 + 1 电容,省料便宜能做大;但电容会漏电,得不停「续命」。
深一层:读一次,伤一次——DRAM 的「破坏性读出」
1 管 1 电容的方案有一个隐藏的麻烦:读 DRAM 是「倒罐子」。字线开闸,电容把自己的电荷全部倒在位线上,由读出放大器判读出是 1 还是 0——倒完,罐子空了,这个 bit 的状态读一次就没了,术语叫破坏性读出(destructive read)。所以 DRAM 每次读操作都自带一个「复原」动作:判读完成后,读出放大器立刻按判读结果把电荷原样充回去。你感受不到这一步,是因为控制器把它焊死在了读流程里;但它解释了 DRAM 的几个脾气——读并不比写快多少(都要动电荷)、每行都配一套读出放大器长驻「值班」、以及后一节要讲的刷新(其实刷新就是「只读不外送、读完即回写」的批量版)。
电容怎么存电荷,也值得钻一眼。DRAM 的电容不是你在电路图里画的那个「两片平板」,而是做成深入硅片的立体微坑或立柱——像在指甲盖大小的面积上,密密麻麻竖起几十亿个比头发丝细万倍的「微型深井」,井壁就是电容的极板。之所以要挖成三维,是因为平面电容太占地方:往「下」挖,不占「地皮」,密度才能一代代往上翻。看到这里你应该有感觉了:内存容量的进化史,就是把这些微井做得更小、更深、更密的历史——每一代工艺大约把单元面积缩到上一代的七八成,容量随之翻倍。
📐 例题 3 内存条的容量账与位宽账:8 颗芯片怎么拼出 8 GB / 64 bit
一条内存板上焊了 8 颗 DRAM 芯片,每颗容量 8 Gb、数据引脚 8 位(这就是常见的 ×8 配置)。(1) 这条内存的总容量是多少 GB?(2) 总数据位宽是多少 bit?(3) 若 CPU 一次访存要取 64 bit,这条内存「恰好」够一次吗?
思路 芯片容量单位 Gb 是十进制位(bit),先换算成字节再乘颗数;位宽直接按「每颗 8 bit × 并联颗数」相加。
解 (1) 每颗:8 Gb = 8×109 bit ÷ 8 = 1 GB。8 颗并联:8 GB。
(2) 位宽:8 颗 × 8 bit/颗 = 64 bit——八颗芯片像八条并行车道,一次同时各交 8 bit。
(3) 64 bit 恰好等于一次访存的需要:刚好够一次取满,不多不少。这不是巧合,而是设计——业界就是按「8 颗 ×8 芯片拼出 64 bit」的惯例来定义内存条规格的。
答:8 GB;64 bit;恰好一次取满。 ⚠ 易错点:① Gb(吉比特)≠ GB(吉字节),差 8 倍——芯片铭牌用小写 b 计 bit,内存条容量用大写 B 计字节,8 Gb 芯片只合 1 GB;② 换算时厂商按十进制(1 GB = 109 B),而系统显示常按二进制(1 GiB = 230 B),所以「标 8 GB 的条子系统显示 7.4x GiB」不是缩水,是两种「尺」;③ 别把 8 颗理解成 8 通道——这 8 颗只是拼出一条 64 bit 的「宽路」,通道是另一层概念(9.6 节)。
📖 工程现场:为什么机载设备偏爱「贴片内存」 一颗 DRAM 芯片能装下 8 Gb,靠的是单元密度极高——但密度越高,每个微井里的电荷越少、越容易被宇宙射线「一击翻盘」。在万米高空,高能粒子击中存储单元造成 0/1 翻转(术语叫单粒子翻转)的概率比地面显著更高。于是航空与航天电子常做三件事:给内存配纠错码(ECC,给数据加冗余校验位,翻一位能自动纠回来)、关键数据双份冗余比对、以及在布局上给敏感电路留「物理间距」。你桌面上的内存条通常没有 ECC,而你手机、笔记本电脑里的那些 DRAM 颗粒,其实天天在替你默默扛着粒子雨。
辨析:1T1C vs 6T——两种单元,两种性格 把本章两位主角的「细胞」并排放好:SRAM 的 6 管单元像一间自带门禁的独立办公室——贵,但推门就办公(读快),且永远在岗(不需维护);DRAM 的 1 管 1 电容像一间超小号的储物柜——便宜到可以海量铺设,但柜门一开就得清点重放(破坏性读出),柜子还会缓慢漏气(需刷新)。结构决定性格,性格决定岗位:办公室圈给缓存,储物柜海铺成内存。存储器没有「更好」的方案,只有「放对位置」的方案。
9.4刷新:DRAM 的「续命」机制
电容漏电,意味着 DRAM 里的 1 会慢慢「流走」变成 0。如果不加干预,几毫秒内数据就全丢了。解决办法是 刷新(refresh):周期性地把每个电容里的电荷「读出来,再原样充回去」,像给漏气的气球定时补气。
所以 DRAM 每隔很短的时间(通常几毫秒),就要把所有单元刷新一遍。这带来几个后果:
- 要额外电路:内存控制器里得有一套「刷新」逻辑,定时扫描所有单元。
- 刷新时不能读写:刷新和正常的读/写会「抢时间」,稍有性能开销。
- 断电即失:一旦断电,没人刷新,电容电荷几毫秒内流光,数据全没。
核心思想:易失性 DRAM 断电即失数据,这叫 易失性存储(volatile memory)。SRAM 其实也易失(断电触发器复位)。所以「内存」都是易失的——这就是为什么你关机后,内存里没保存的数据会消失,而硬盘里的文件还在。想永久保存,得靠下一章的非易失存储。
🧠 一句话记忆 DRAM 靠「定时补气」续命;一断电就忘光——所以内存是「易失」的。
深一层:刷新到底在刷什么?
「把电荷读出来再充回去」说起来一行,里面藏着两个关键细节。其一,刷新不是逐个单元刷,而是一行一行刷:控制器发一个「行刷新」命令,字线一开,这一整行的所有电容同时倒进各自配对的读出放大器,放大器判读完立刻原样回充——一行数千个 bit 一次搞定。内存芯片被划分成几千行,控制器按轮盘表挨个点名。其二,刷新不需要把数据送到 CPU 再送回来:整个「读出-回充」在芯片内部就完成了,外面只看见总线忙了一下。所以刷新更像「每晚巡楼检查每间房并顺手把快熄的灯拧亮」,而不是把房里的东西搬出去再搬回来。
刷新的节拍也有讲究:电容漏电的快慢随温度上升而加剧——室温下 64 ms 刷完一轮即可,高温下可能要求收紧到 32 ms 甚至 16 ms。这就是为什么内存数据手册里刷新周期标着「≤85 °C 时 64 ms,85~95 °C 时 32 ms」之类的分档。对机载、车载这类宽温环境(设备舱温度能摸到七八十度),控制器必须动态切换刷新频率,否则误码率会悄悄爬升——「续命针」的频率,得看体质下处方。
📐 例题 4 刷新要花掉多少「时间税」?
某 DRAM 芯片共 8192 行,要求每 64 ms 把所有行刷新一遍(每隔相同时间刷一行)。设一次行刷新耗时 50 ns。(1) 平均每多久要刷一行?(2) 64 ms 内因刷新总共占用多少时间?(3) 刷新开销占运行时间的比例是多少?
思路 轮盘式平摊:周期 ÷ 行数 = 行间间隔;总占用 = 行数 × 单次耗时;比例 = 总占用 ÷ 周期。
解 (1) 间隔 = 64 ms ÷ 8192 = 64 000 μs ÷ 8192 = 7.8125 μs——平均每 7.8 微秒点一行,一天要点约 110 亿次。
(2) 总占用 = 8192 × 50 ns = 409 600 ns = 0.4096 ms。
(3) 比例 = 0.4096 ÷ 64 = 0.64%。
答:每 7.8125 μs 刷一行;每轮共占 0.4096 ms;开销约 0.64%。 ⚠ 易错点:① 7.8125 μs 这个数其实是行业惯例 tREFI(行刷新间隔)的来源,别当成随便取的值;② 开销虽小,但它是「死时间」——恰逢刷新的读请求要排队;且芯片容量越大、行数越多、单行刷新越久(大容量芯片 tRFC 已涨到数百 ns),实际「刷新税」会更高;③ 高温下周期从 64 ms 收紧到 32 ms,刷的次数翻倍、税也翻倍——但这换回的是数据可靠。
📖 工程现场:「睡眠」的内存为什么数据还在? 手机放着不动、笔记本合盖待机,耗电骤降但已存数据并不丢——靠的是 DRAM 的自刷新(self-refresh)模式:控制器把「点名表」交给芯片内部的一个小电路后撒手不管,时钟降频、接口断电,只有刷新电路拿极小的电流持续「巡楼」。数据因此保住了,功耗却压到正常运行的百分之一量级——这就是「休眠而不失忆」的幕后机关。下一次你合上笔记本再打开,一切如初,那是几十亿次默默补气的功劳。
再补一个与安全攸关系统相关的常识:飞机、汽车的计算机每次上电都要跑上电自检(Power-On Self-Test),其中内存检查几乎必在清单上——写入已知图案(如 0101 交替、走步 1 图案)到每个区域、再读回比对,确认没有「锁不住的 bit」;带 ECC 的系统还要确认纠错电路本身在岗。乘客登机时驾驶舱里那句「自检通过」,背后正包含着这样一场针对几十亿个储物柜的快速点名。消费电子开机时的短暂黑屏延迟,同一件事的低配版。
辨析:刷新、读后重写、自刷新——三个「回充」别混淆 三者动作相似、场合不同:读后重写是被动跟随——因为读出是破坏性的,读一次必须立即补一次,发生在「访问到它」时;刷新是主动巡检——不管你读不读,定期把电荷续上,防的是漏电;自刷新是托管模式——整机休眠时芯片自己给自己续命。一句话收拢:读后重写补「读的伤」,刷新补「漏的气」,自刷新是「没人管了也得活着」。
9.5内存寻址:地址如何选中一个单元
内存里有几十亿个存储单元,CPU 怎么精确地「点」到它想要的那一个?靠 寻址(addressing)。
存储单元被排成一个二维矩阵(像一张大表格),每个单元有「行」和「列」。CPU 给出一个地址,内存控制器就把它拆成行地址 + 列地址,然后:
- 用行地址选中那一行(通过译码器,点亮一条字线)。
- 用列地址选中那一列(通过多路选择器,接通一条位线)。
- 行列交叉的那个单元,就是目标——读出或写入它。
这里你看到了第 5 章译码器、多路选择器的用武之地——它们就是「点兵点将」的硬件实现。
🧠 一句话记忆 寻址 = 行列交叉定位;译码器选行、多路选择器选列。
深一层:为什么非排成矩阵?——一场「导线的经济学」
存储单元排成一长排不行吗?行,但导线会先把你压垮。假设有 4096 个单元排成一维,每单元一根专属选择线,就要从译码器拉出 4096 根线;改排成 64×64 的矩阵,则只需要 64 根行线 + 64 根列线 = 128 根,一下子省去 9696 根。单元越多省得越狠:真要把几十亿单元一维排开,导线的数量将超过单元本身,芯片直接变成「电线罐头」。矩阵结构用「行×列」两根坐标代替「一单元一线」——地址的本质(两个坐标的编号)与内存的物理形状(行列矩阵),在这里严丝合缝地对上了。这也是 8.2 节「地址」概念的下半场:地址不只是编号,更是一套用最少的线选中任意一点的编码方案。
顺着「省线」的思路再走一步,就到了地址复用:既然行列是两串坐标,物理引脚可以只留一排「地址引脚」,先送行地址、锁存,再送列地址——两次分时复用同一组线。例如 1 GiB 内存需要 30 位地址(230 = 1 073 741 824 个可寻址字节),按行列各半拆分,物理地址引脚只要 15 根。内存芯片引脚越少,封装越小、走线越省,这又是工程在「时间换空间」上的一次小小胜利。
核心深化:局部性——「金字塔」能转起来的真正土壤
本章至此还剩最后一个关键问题:缓存凭什么敢只装几 MiB,就赌它命中 CPU 要的大部分数据?答案是程序与生俱来的一种「习性」,叫 局部性原理(principle of locality)。它有两条:
- 时间局部性:刚被访问过的数据,很快还会被访问。循环变量、累加器、常用的函数参数——每个循环里都要摸几十上百遍。
- 空间局部性:刚被访问的数据旁边的,很快也会被访问。数组从 a[0] 扫到 a[1]、a[2]……指令一条挨一条往下走,都是「顺手就拿下一个邻居」。
局部性还有一层与本章硬件的呼应:行缓冲。9.5 节说过激活一行时,整行数据会躺进读出放大器阵列里「候着」——如果你接下来访问的恰是同一行的邻居(空间局部性的直接后果),内存可以跳过最慢的「重新激活行」步骤直接命中,快出一大截。DRAM 的设计者很早就把局部性焊进了芯片的访问流程里;而缓存(SRAM)则是把这个思想再往前推一层——把「可能马上要用的邻居们」整个搬到 CPU 身边。一句话:金字塔能运转,是因为程序自己「恋旧又恋邻」;硬件只是顺势而为。
📐 例题 5 矩阵的导线账 + 1 GiB 的地址账
(1) 把 4096 个存储单元排成一维,每单元一根选择线,共需多少根线?改排成 64×64 矩阵后呢?(2) 一块 1 GiB 的内存按字节编址,需要多少位地址?(3) 若行列地址分时复用同一组引脚,且行列各用一半位数,物理地址引脚最少需要多少根?
思路 (1) 一维:单元数即线数;矩阵:行线数 + 列线数。(2) 按「n 位地址可编 2n 个单元」找 n 使 2n ≥ 1 GiB = 230。(3) 复用 = 位数减半。
解 (1) 一维需 4096 根;64×64 矩阵需 64 + 64 = 128 根,只有一维方案的 1/32。
(2) 1 GiB = 230 字节,按字节编址需 30 位地址。
(3) 行列各 15 位,分时复用同一组引脚:15 根。
答:4096 根 → 128 根;30 位地址;15 根复用引脚。 ⚠ 易错点:① GiB 是 2 的幂,1 GiB = 230 B,别按 109 算出「约 30 位」的侥幸答案;② 矩阵未必方正(实际芯片行长列短,行数少列数多),题中取方阵只为说明原理;③ 复用虽省引脚,却让一次访存变成「送行地址、送列地址、等数据」三段,这正是 DRAM 接口延迟高于 SRAM 的原因之一——省与快,永远在打架。
📖 工程现场:局部性也是工程直觉 局部性不只是硬件设计者的理论,它几乎是所有数据工程的第一直觉:数据库把「相关的行」尽量放同一页,让一次读盘带出一批(空间局部性);航电软件把高频任务的数据放同一片存储区,把冷数据外移(时间局部性);甚至于你整理工具车间的原则——常用的放手边、同类的一起放——也是同一个思想的行业版。理解了局部性,你再看任何「分层缓存 + 批量搬运」的系统,都能一眼认出它的骨架。
当然,也要知道局部性「失灵」的时刻,免得把它当成铁律:程序里指针追逐(一个节点指向的下一个节点在内存里七零八落)、大范围随机散布(按散列值跳着访问巨型表格)这类访问模式,「下一个邻居」无从猜起,空间局部性几乎归零;缓存只能靠「反复访问」那点时间局部性苟着,命中率骤降、性能直线下坠。工程界给这类现象起了名字(如「指针跳跃毁缓存」),也发展出对策:把链表节点「预取拍平」成连续数组、按访问热度重排数据、调整数据结构的布局顺序。硬件给了统计规律,软件就得顺着规律安排数据——性能调优的半壁江山,就是「让数据住得符合局部性」这一件朴素的事。
衔接:SRAM 缓存 = 局部性的变现器 现在把本章两条线拧起来:SRAM 快而小、DRAM 大而廉,中间靠什么衔接?靠缓存——它是一小块 SRAM,蹲在 CPU 与 DRAM 之间,把「时间上会反复用、空间上住得近」的数据块收编进来,让绝大多数访存(九成以上)落在它这里完成,只有少数「漏网之鱼」才付 300 拍的代价去 DRAM 取。局部性是「原料」,缓存是「变现器」,金字塔的每一层都是这么运转的——这套机制,会在后续章节反复出现。
9.6内存条与通道:把 DRAM 装进电脑
单颗 DRAM 芯片容量有限,实际的内存是把很多颗 DRAM 芯片焊在一块小电路板上,做成我们熟悉的 内存条(DIMM,Dual In-line Memory Module)。内存条插在主板的内存插槽上,通过内存总线与 CPU 相连。
为了更快,现代电脑还引入了 通道(channel)概念:
- 单通道:数据只能走一条路进出。
- 双通道(甚至四通道):用两条(多条)并行的路同时传数据,带宽翻倍,就像从单车道扩成双车道。
| 特性 | SRAM | DRAM |
|---|---|---|
| 存储原理 | 触发器 | 电容电荷 |
| 每 bit 元件数 | 4–6 晶体管 | 1 晶体管 + 1 电容 |
| 速度 | 快 | 较慢 |
| 成本 / 密度 | 贵、占面积 | 便宜、高密度 |
| 是否刷新 | 否 | 是 |
| 典型用途 | CPU 缓存 | 内存条(主存) |
🧠 一句话记忆 SRAM 快而贵(做缓存),DRAM 大而廉(做内存条);双通道 = 双车道提速。
深一层:带宽的账怎么算?——位宽 × 速率
内存的「快慢」其实有两个维度:延迟(latency,一次访问要等多久,纳秒级)和带宽(bandwidth,单位时间能搬多少字节)。通道技术改善的是后者,公式一行:
公式里藏着一个高频混淆点:传输速率的单位是 MT/s(每秒百万次传输),而 DRAM 的「DDR」三个字母正是指Double Data Rate(双倍数据速率)——时钟的上升沿与下降沿各传一次,一拍当两拍用。所以 DDR4-3200 的工作时钟其实只有 1600 MHz,传输速率却是 3200 MT/s:标称数字是「传」,不是「振」。这也是内存世界 MHz 与 MT/s 常被混用又必须分清的原因。
双通道的原理,是给内存配两个彼此独立的控制器与通路,让系统把连续地址交错分配(奇数段给通道 A、偶数段给通道 B):CPU 要一段连续数据时,两个通道各搬一半,并行完成——单车道扩双车道,一次通行的车数翻倍。注意它不缩短任何一次访问的延迟(每辆车过桥的时间没变),只是让「同时在路上」的车翻倍——又一次,是吞吐而非延迟的胜利(对比第 8 章流水线,思想完全同源)。
📐 例题 6 单通道 vs 双通道:带宽与耗时各差多少
一条 DDR4-3200 内存(位宽 64 bit,传输速率 3200 MT/s)。(1) 单通道带宽是多少 GB/s?(2) 组成双通道后带宽是多少?(3) 要把一个 4 GB 的数据集从内存搬给 CPU 处理,双通道比单通道理论上节省多少时间?
思路 套公式:带宽 = 位宽 ÷ 8 × 速率;耗时 = 数据量 ÷ 带宽。双通道带宽翻倍、耗时减半。
解 (1) 单通道:64 ÷ 8 × 3200×106/s = 8 B × 3200×106 = 25.6×109 B/s = 25.6 GB/s。
(2) 双通道:带宽翻倍 = 51.2 GB/s。
(3) 单通道耗时:4×109 ÷ 25.6×109 ≈ 0.156 s;双通道:4×109 ÷ 51.2×109 ≈ 0.078 s,节省约一半。
答:25.6 GB/s;51.2 GB/s;0.156 s → 0.078 s。 ⚠ 易错点:① 别把 3200 MT/s 当 3200 MHz——时钟其实是 1600 MHz,靠上下双沿翻到 3200;② GB 与 GiB 别混:题目按十进制 109 口径统一计算即可;③ 双通道要求内存条成对插入指定的成对插槽(且两条容量/规格最好一致),插错了就退化回单通道——「装机要让双通道生效」是装机员的常识。
现在能回答批注在小节标题里的问题了:为什么 64 位 CPU 总要配双通道甚至四通道?一拍一取的视角最直观:CPU 的数据通路是 64 位宽,一次访存恰好吃满单通道的 64 位——带宽「够一次用」,但架不住 CPU 每拍都想要。真正的原因是供需速率差:CPU 每秒发出的数据需求远超单通道能供的量(3 GHz 的处理器满负荷时每秒要几千亿字节的吞吐,单通道 25.6 GB/s 连百分之一都喂不满),于是必须靠多通道并行、多通道交错把供给翻上去。位宽 64 是「每一口的大小」,通道数是「嘴巴张开的数量」——口大不等于吃得多,还得嘴多。
📖 工程现场:没有独立显卡的电脑,为何这么依赖内存带宽 用处理器里集成的显示单元打游戏或做图形处理时,画面数据全部要走「内存」这同一条大动脉——显存就是主存,绘图单元和 CPU 在同一条通道上抢带宽。此时内存带宽直接变成帧率的瓶颈:同样的机器,插两条内存组双通道,画面帧数常能比单条提升三到五成。装机圈流传的「核显吃内存、双通道是免费性能」,道理全在本节公式里——把带宽公式算一遍,你就比大多数装机教程都懂行。
辨析:延迟与带宽——两条独立的快慢轴 内存常有「更高频的条子反而延迟更差」的反直觉现象,根源在此:延迟看的是「一次访问从发问到数据到手」的总时间(受行激活、列选通、电路训练等一串环节影响,单位常以拍数计);带宽看的是「水管粗细 × 流速」。提频会加粗水管(传输速率升),但每个环节的拍数可能变多,绝对延迟未必降。日常体感排序:小而碎的随机访问吃延迟(查字典页数多最烦),大块连续的数据搬运吃带宽(一次搬一卡车)。工程上「鱼与熊掌」都要兼顾——这也是后续章节里存储系统反复出现的评价坐标。
收束成三条可以带走的选购直觉:① 容量优先——内存不足引发换页,是「万倍级慢」的灾难,比任何频率差异都伤体验;② 成对插满——双通道是免费翻倍的带宽,只差把第二条插到正确插槽;③ 频率看整体——内存条标称的 MT/s 要与 CPU 内存控制器、主板支持档位一致才能全速,木桶效应在内存上格外明显。至此,「SRAM 与 DRAM 的性格差异 + 寻址的行列结构 + 局部性规律 + 带宽账本」四件套齐了,下一章离开易失世界,去看关机后数据凭什么还在。
本章小结
- 内存是 CPU 的工作台,处于「存储金字塔」的速度与容量折中处。
- SRAM 用触发器存 bit,快而稳、无需刷新,但贵——用于缓存。
- DRAM 用「1 晶体管 + 1 电容」存 bit,省料便宜,但电容漏电需刷新——用于内存条。
- 内存是易失性存储,断电即失。
- 寻址靠「行列交叉」:译码器选行、多路选择器选列;内存条通过通道并行提升带宽。
读完本章,你应该能……
- 画出(或描述)存储金字塔的层次,说出内存的位置。
- 解释 SRAM 为什么快但贵(触发器,多晶体管)。
- 解释 DRAM 为什么便宜但需要刷新(电容漏电)。
- 说清「易失性」的含义,并解释为什么关机后内存数据会丢。
- 描述「行地址 + 列地址」如何定位一个存储单元。
思考题
1. SRAM 和 DRAM 各自用什么物理机制存一个 bit?
提示:SRAM 用触发器(交叉耦合晶体管);DRAM 用电容存电荷(有电=1,无电=0)。
2. 为什么 DRAM 能比 SRAM 做得更大更便宜?代价是什么?
提示:每 bit 只要 1 管 + 1 电容,省料;代价是电容漏电,需要刷新,速度也慢。
3. 「内存是易失性的」是什么意思?这和「刷新」有什么关系?
提示:断电即失数据;DRAM 靠不断刷新维持,一断电没人刷新,电荷流光。
4. CPU 给出一个地址后,内存如何精确选中那个单元?
提示:地址拆成行地址 + 列地址,译码器选行、多路选择器选列,交叉点即目标。
5. 一条 DDR5-4800 内存(64 bit 位宽),单通道带宽是多少 GB/s?
提示:带宽 = 位宽 ÷ 8 × 传输速率 = 64 ÷ 8 × 4800×106 B/s = 38.4 GB/s。同规格组双通道即 76.8 GB/s——高频条配多通道,就是「大口径 × 多车道」的叠加。
6. 为什么机载、车载电子设备在高温环境下,内存控制器要自动加大刷新频率?
提示:温度越高,电容漏电越快,64 ms 的刷新周期在高温下不够保险,须收紧到 32 ms 甚至 16 ms——宁可多花一点「刷新税」,也不冒误码的风险;这是用性能换可靠性的典型工程权衡。
7. 循环里反复读写累加变量 s、又顺序扫描数组 a[0]、a[1]、a[2]……分别体现了哪一种局部性?两者对缓存的启示有何不同?
提示:s(还有循环变量 i)体现时间局部性——把最常摸的放最近处;a 的顺序访问体现空间局部性——要取下一个就顺带把一整块邻居搬进缓存。前者说「常用的留在缓存」,后者说「一次搬一整块」,两条合起来就是缓存与预取的全部思想。
8. 寄存器(第 6 章)、CPU 缓存、主存三层都负责「记住数据」,为什么偏偏是「寄存器与缓存用 SRAM、主存用 DRAM」这样的分工?
解析:三层共同诉求都是「快」,但容量压力天差地别。寄存器与缓存长在 CPU 内部、离运算电路最近,必须一拍内出结果,于是用 SRAM——触发器直读直写、不用刷新、无破坏性读出,代价是每位要 4–6 个晶体管、密度低价格高,好在缓存容量只要求 KB 到 MB 级;主存要装下 GB 级的程序与数据,密度与价格是生死线,只能退而求其次用 DRAM——1 管 1 电容便宜百倍,容忍刷新税与破坏性读出,再靠刷新机制与行列寻址把慢的部分藏起来。一句话:越靠近 CPU 的层越买「快」,越靠下的层越买「多」——存储金字塔的每一层,都是这笔交易的一次成交。