L03:缓存组织与内存管(Cache Organization and Memory Management)
MIT 6.5900 Fall 2024 · Daniel Sanchez 主题:放置/替换策略、缓存性能与缺失分类、块级与多级优化、内存管理演进(绝对地址→分页→按需分页)
一、缓存基础回顾
Cache 中每个行(line)含 Tag + 数据块,是主存某位置的副本。
读算法:用处理器地址搜索 Cache tag 找匹配——命中(HIT)则从 Cache 返回数据副本;缺失(MISS)则从主存读入数据块、返回处理器并更新 Cache(需决定替换哪一行)。
放置策略(Placement Policy)
块 12 在 8 块 Cache 中可放在:
| 策略 | 可放位置 |
|---|---|
| 直接映射(Direct Mapped) | 只能放第 4 块( |
| 全相联(Fully Associative) | 任意位置 |
| 组相联(Set Associative,2 路) | 第 0 组任意路( |
替换策略(Replacement Policy)
从一组中逐出哪一块?
- 随机(Random);
- 最近最少使用(LRU):每次访问都要更新 LRU 状态;真实实现只对小组(2–4 路)可行,8+ 路常用伪 LRU 二叉树;
- 先进先出(FIFO / Round-Robin):用于高相联度 Cache;
- 非最近使用(NLRU):FIFO 但对最近使用的块例外;
- 一位 LRU:每路一位,使用时置位,替换第一个未用的。
多策略竞争:用一个计数器,按 Policy A/B 在不同采样组上的缺失情况增减,从而为程序选最佳替换策略。
二、缓存性能与缺失分类
平均访存时间(AMAT)
提升性能的途径:降低命中时间、降低缺失率(更大/更好策略)、降低缺失代价(如加 L2)。
最简单的设计策略:在不把命中时间推过 1–2 周期的前提下用最大的 Cache(现代约 16–64 KB)。
缺失的三种原因(3C)[Hill, 1989]
- 强制缺失(Compulsory):首次引用某块(冷启动),即使无限大 Cache 也会发生;
- 容量缺失(Capacity):Cache 太小放不下程序所需数据,即使全相联 + 完美替换也会发生;
- 冲突缺失(Conflict):因块放置策略碰撞而来,全相联下不会发生。
缓存参数对性能的影响
| 参数 | 强制 | 容量 | 冲突 | 命中延迟 | 缺失延迟 |
|---|---|---|---|---|---|
| 更大容量 | — | 降 | 降 | 升 | — |
| 更高相联度 | — | — | 降 | 升 | — |
| 更大块(假设有空间局部性) | 降 | — | 可能升 | — | 升 |
三、块级与多级优化
块级优化
- tag 太多(开销大)时:简单办法是用更大的块,但缺失代价可能很大;
- 子块放置(Sub-block / Sector Cache):在比整块更小的单元上加有效位,缺失时只读一个子块;tag 匹配后仍需看子块是否在 Cache 中。
多级 Cache
内存不可能又大又快,加多级 Cache 降低缺失代价(每级延迟更长、容量更大)。
度量:本地缺失率(= 该 Cache 缺失/对该 Cache 的访问)、全局缺失率(= 该 Cache 缺失/CPU 访存)、每指令缺失数(MPI)。
包含策略(Inclusion Policy)
| 策略 | 特征 | 例子 |
|---|---|---|
| 包含式(Inclusive) | 内层是外层的子集;外层替换会作废内层;外部访问只需查外层 | Intel 至 Broadwell |
| 非包含式(Non-inclusive) | 内层可含外层没有的数据 | Intel Skylake, ARM |
| 互斥式(Exclusive) | 内外层数据不同;缺失时交换行 | AMD |
牺牲者缓存(Victim Cache)[HP 7200]
在直接映射 Cache 旁加一个小的全相联备份 Cache,存放最近被逐出的行。先查直接映射 Cache,缺失则查牺牲者缓存;命中则与 L1 当前逐出行交换。
兼得直接映射的快命中与更少的冲突缺失。
四、内存管理的演进
内存位置的命名
- 机器语言地址:机器码指定的地址;
- 虚拟地址(Virtual Address):ISA 把机器码地址翻译成程序变量的虚拟地址(有效地址);
- 物理地址(Physical Address):OS 指定虚拟地址到物理位置的映射。
绝对地址(50 年代)
一次只跑一个程序,对整机无限制访问,虚拟地址 = 物理地址。位置无关靠链接器/加载器修改子程序与调用者的地址。
多道程序(Multiprogramming)
为重叠 CPU 与 I/O 提高吞吐而生,引出三类需求:
- 基址寄存器(Base Register):支持位置无关程序、简化编程与存储管理;
- 界限寄存器(Bound Register):保护,使独立程序不互相影响;
- 基址/界限寄存器仅在管理模式(supervisor mode)下可见可访问。
也可为代码段与数据段分设基址/界限(X1 之前的 Cray 向量机用此方案)。
内存碎片(Fragmentation)
用户来去使存储碎片化,某阶段须移动程序以压缩存储。
分页内存系统(Paged Memory)
把每个进程的虚拟地址空间管理为小的固定大小页(如 4KB),让 OS 把各页非连续地存于物理内存。
- 处理器产生的地址解释为
<页号, 偏移>; - 页表(Page Table)存每页基址的物理地址,使非连续存储成为可能;
- 每个用户有自己的页表,页表对每个用户页有一项。
页表存哪里?所需空间正比于地址空间×用户数,太大不能放寄存器;放主存则每次访问需两次访存(取页基址 + 取数据)→ 引出 TLB(缓存常用页的地址翻译)。
按需分页(Demand Paging)
早期许多应用数据放不进主存,分页减少碎片但仍需整个程序常驻。手动 overlay(手工或软件地址翻译)困难且低效。
Atlas(1962):把次级存储(鼓)的页在被处理器隐式需要时自动调入主存(Kilburn)——把主存当作次级存储的 Cache。用每个页框一个页地址寄存器(PAR),把有效页地址与全部 32 个 PAR 比较:匹配则正常访问,不匹配则缺页(保存部分执行指令的状态)。缺页时调入空闲页、更新 PAR、无空闲页则按使用情况替换并写回鼓。
Caching vs 按需分页对比
| Caching | 按需分页 | |
|---|---|---|
| 单位 | cache 块(~32 B) | 页(~4 KB) |
| 缺失率 | 1%–20% | <0.001% |
| 命中 | ~1 周期 | ~100 周期 |
| 缺失 | ~100 周期 | ~5M 周期 |
| 缺失处理 | 硬件 | 大部分软件(OS) |
小结
- Cache 由放置(直接/组相联/全相联)、替换(LRU/FIFO/伪 LRU 等)策略决定,性能用 AMAT 与 3C 缺失(强制/容量/冲突)刻画;
- 块级(子块)与多级(包含/非包含/互斥、牺牲者缓存)优化在容量、延迟、tag 开销间权衡;
- 内存管理从绝对地址 → 基址/界限分段 → 分页(解决碎片)→ 按需分页(运行超过主存的程序),核心代价是每次访存的地址翻译。
下一讲:现代虚拟内存系统