主存怎么造(DRAM)+ 主存不够怎么办(虚拟内存)——存储层次思想在「主存-磁盘」尺度的复刻,OS 内存管理的硬件底座。
| SRAM | DRAM | |
|---|---|---|
| 存储单元 | 6 个晶体管(触发器) | 1 晶体管 + 1 电容 |
| 刷新 | 不需要 | 要周期刷新(电容漏电) |
| 速度 | 快(纳秒级) | 慢 |
| 密度/成本 | 低/贵 | 高/便宜 |
| 用途 | Cache(第 7 章) | 主存 |
注意:DRAM 电容漏电,必须每隔几十毫秒刷新一次(重写所有行)否则数据消失。刷新占用访存带宽——这是「DRAM 延迟不稳定、比 SRAM 慢一个量级」的物理根源,也是 Cache 必须存在的原因(第 7 章内存墙)。
DRAM 是二维阵列,地址拆成行地址+列地址,RAS/CAS 两根选通分时复用同一组地址线(省引脚):
访存流程:先 RAS 选行(整行读入行缓冲/感测放大器)
再 CAS 选列(从行缓冲里挑出目标单元)
行缓冲命中(row buffer hit):连续访问同一行(空间局部性)就快,跨行要重新激活、慢得多。SDRAM/DDR 的「DDR」= 时钟上下沿都传数据,带宽翻倍。
对比:DRAM 的行/列组织是空间局部性的硬件体现——顺序访问数组=同一行连续列、快;随机访问=频繁换行、慢。从寄存器到磁盘,每层都奖励顺序、惩罚随机。
每个进程看到一个独立、连续、比物理内存大的虚拟地址空间,由 MMU+OS 翻译成物理地址。
虚拟地址 = 虚拟页号 VPN | 页内偏移 offset
│ 查页表(MMU + TLB)
▼
物理地址 = 物理页框号 PFN | 页内偏移 offset(不变)
注意:虚拟内存给每进程「独占整块内存」的错觉,是进程隔离与安全的硬件基石——一进程的虚拟地址只有经自己页表才能落物理地址。这也是野指针访问非法地址 → SIGSEGV 的机制:MMU 发现无映射/无权限,触发缺页/保护异常,内核发段错误。
查页表本身要访存(多级页表多次访存),慢。TLB(快表) 是「VPN→PFN」专用 Cache:
CPU 发虚拟地址 ──▶ 先查 TLB(快,命中则直接得物理地址)
│ 未命中 ──▶ 查页表(慢)──▶ 装入 TLB
对比:TLB 之于页表正如 Cache 之于主存——都是小快缓冲挡在大慢结构前,都靠局部性(TLB 命中靠时间局部性:反复访问同一批页)。「TLB 缺失→查页表→可能缺页→换页」是越来越慢的链条。
| 层次 | 挡在谁之间 | 缓冲什么 | 缺失代价 |
|---|---|---|---|
| Cache | CPU ↔ 主存 | 内存块 | 主存延迟 |
| TLB | MMU ↔ 页表 | 页表项 | 页表访存 |
| 页表 | 进程 ↔ 物理内存 | 虚拟↔物理映射 | 缺页(磁盘!) |
mmap 把文件映射进虚拟地址空间 = 让文件页按需换入,虚拟内存思想在文件 I/O 的复用。malloc/new 分配的是虚拟地址,物理页到真正读写才分配(惰性分配);Java GC、Python 引用计数都运行其上。