
目录
[2020年代计算机系统(AMD Zen 4)的缓存、内存和外部存储层级结构](#2020年代计算机系统(AMD Zen 4)的缓存、内存和外部存储层级结构)
[有些 CPU 在 L3 和内存之间加 L4](#有些 CPU 在 L3 和内存之间加 L4)
[什么是 Memory Tiering?](#什么是 Memory Tiering?)
[Linux 怎么实现 Memory Tiering?](#Linux 怎么实现 Memory Tiering?)
[1. 基于 NUMA 扩展](#1. 基于 NUMA 扩展)
[2. 用"热页"迁移](#2. 用"热页"迁移)
[3. 加权交错分配(Weighted-interleave)](#3. 加权交错分配(Weighted-interleave))
[放眼当今2026 年](#放眼当今2026 年)
当 CPU 需要数据时,如果高层(比如 Cache)里没有 ,就要去低层(比如内存) 取。因为低层慢,CPU 就得"干等",这叫等待延迟(latency)。
为了减少这种等待,硬件会自动做以下事情:
- 预测:CPU 或内存控制器会"猜"你接下来可能需要什么数据
- 提前取 :不等 CPU 要,就提前把低层的数据搬到高层(比如从内存预取到 Cache)
- 填充缓冲区:把取来的数据先放到一个临时缓冲区里
- 发出激活转账信号:通知相关部件"数据准备好了,可以传输了"
这样做的好处是:等 CPU 真正需要数据时,数据已经在高层了,不用等。
一种通用的存储器层级结构
- 内部------ 处理器寄存器和缓存。
- 主接口------系统内存和控制卡。
- 在线大容量存储------二级存储。
- 离线散装储存------三级和离线储存。
存储层级在实际工程中的核心矛盾与优化方向
性能与复杂性的矛盾
我们加 Cache、加预取、加乱序执行,不就是为了更快吗?为什么反而说"增加复杂性会拖慢"?
原因在于:每一层额外的控制逻辑都会引入延迟。
举个例子:
| 增加的东西 | 带来的好处 | 付出的代价(延迟) |
|---|---|---|
| 多级 Cache | 命中率提高 | 每一级都要做标签查找(tag lookup)、一致性检查 |
| 预取器 | 提前把数据搬上来 | 需要额外的预测逻辑、可能污染 Cache |
| 虚拟内存 | 程序隔离、方便 | 每次访存要多做一次**页表翻译(TLB 查找)** |
复杂性不是免费的。每增加一层抽象或控制,CPU 在"找到数据"之前就要多做一步判断。如果这个判断本身很耗时,反而会抵消掉"数据在高层"带来的好处。
性能优化的核心原则
这句话是整个内存层级设计的终极目标,也是程序优化的核心原则。
**"how far down"** 就是访问延迟的量级:
| 需要去到第几层 | 大概延迟(现代 CPU) | 性能代价 |
|---|---|---|
| L1 Cache | ~1 ns | 几乎无代价 |
| L2 Cache | ~3-4 ns | 很小 |
| L3 Cache | ~10-20 ns | 可接受 |
| 主内存 | ~60-100 ns | 已经很慢了 |
| SSD | ~100 μs | 慢了 1000 倍 |
| 硬盘 | ~10 ms | 慢了 10 万倍 |
核心思想:每往下一层,延迟就跳一个数量级。所以:
- 算法设计:尽量让数据留在高层(时间局部性 + 空间局部性)
- 数据结构设计:紧凑排列,提高 Cache 命中率
- 编程技巧:循环分块(loop tiling)、 prefetch 指令
性能 = 尽量在"高处"把事情做完
AI 训练里一次 HBM miss 去 NVMe 加载权重,等于白跑几百万次 FLOP 。所以 2026 年所有大模型推理优化(KV-cache 分页、PagedAttention、context memory offload)本质都是这句话的翻版:
别往下走,往下走一次,token 就少一半。
延迟和带宽的非均匀性
一个容易被忽略但极其重要的事实 :内存层级中,不同层的延迟和带宽差异巨大,且不能用一个统一模型描述。
延迟(Latency)= "拿到第一个字节要多久"
CPU 寄存器 → 0 周期
L1 Cache → 3-4 周期
L2 Cache → 10-12 周期
L3 Cache → 30-40 周期
主内存 → 200-300 周期
带宽(Bandwidth)= "每秒能搬多少数据"
L1 Cache → ~1-2 TB/s(非常高)
L2 Cache → ~500 GB/s
L3 Cache → ~200 GB/s
主内存 → ~50 GB/s(相对低很多)
"非均匀"的含义:
- 延迟非均匀:从 L2 到 L1 可能只要多等 3 个周期,但从内存到 L3 要多等 200 个周期
- 带宽非均匀:高层带宽极高但容量极小,低层容量大但带宽反而受限(内存总线是共享的)
- 不同组件差异巨大:你不能说"Cache 延迟是 X",因为 L1、L2、L3 的延迟完全不同
工程意义 :写高性能程序时,必须针对具体哪一层来优化。比如:
- 对 L1 友好的代码(小循环、连续访问)和对内存友好的代码(批量 DMA 传输)策略完全不同
- 乱用 prefetch 可能反而降低性能,因为预取本身占用内存带宽
预测数据位置的困难
硬件和软件都面临的一个根本性难题 :你不知道数据现在"在哪一层"。
原因很复杂:
1. 硬件层面的不确定性
-
Cache 是硬件自动管理的,程序员不可见
-
你写的变量可能在 L1、可能在 L2、可能已经被换出到内存、甚至可能被其他程序挤掉了
-
多核 CPU 中,另一个核可能修改了数据,导致你这边的 Cache 行失效(Cache coherence)
2. 软件层面的不确定性
-
操作系统可能把你的内存页换出到磁盘(swap)
-
虚拟内存让物理位置对程序透明
-
多线程/多进程共享资源,互相干扰
3. 后果很严重
- 如果预测错了(以为在 L1,实际在内存),性能直接掉一个数量级
- 预取器如果预测错了,不仅白忙活,还污染了 Cache(把有用的数据挤走了)
这就是为什么现代 CPU 花了大量晶体管在做分支预测 + 预取预测------本质上就是在赌"数据在哪"。
预取延迟取决于位置
- 预取(prefetch)= 提前把数据从低层搬到高层
- 从哪搬、搬到哪,决定了预取本身要花多少时间
具体来说:
| 预取场景 | 需要的时间 | 原因 |
|---|---|---|
| 从 L2 预取到 L1 | ~10 周期 | 距离近,总线快 |
| 从内存预取到 L3 | ~200 周期 | 要过内存控制器、DRAM 延迟 |
| 从 SSD 预取到内存 | ~100 μs | 要发起 I/O 请求、等磁盘寻道 |
关键工程含义:
- 预取必须"提前足够多":如果你从内存预取需要 200 周期,那你至少要在 200 周期之前就发出预取请求,否则 CPU 还是得等
- 预取距离要匹配层级深度 :
- 对 L1:提前几条指令就够了
- 对内存:需要提前几百条指令甚至更早
- 对磁盘:需要提前几毫秒(操作系统级的 readahead)
- 预取太早也有问题:数据可能被挤走(Cache 被其他东西填满了)
预取本身在 2026 年已经不是"CPU 指令"概念,而是 硬件预取 + OS 页迁移 + 运行时 offload 的三层叠加 。
2020年代计算机系统(AMD Zen 4)的缓存、内存和外部存储层级结构

有些 CPU 在 L3 和内存之间加 L4
- 2026 年还有没有"L3 和内存之间的一层"?有,但换形态了 :
- Intel :Meteor Lake / Arrow Lake 后提出 Adamantine L4 (封装内大缓存,Linux 补丁里叫 adamantine,128 MB--GB 级,给 iGPU/CPU 用);此外 CXL Type-3 内存扩展卡在系统软件眼里就是"L3 之下、DRAM 之下的另一层可缓存/可迁移内存"。
- AMD :不叫 L4,而是 3D V-Cache 把 L3 堆到 96--128 MB/CCD(Zen 4 X3D、Zen 5 X3D),EPYC 上 L3 总量可达 768 MB+;本质是把"L3 和 DRAM 之间的缓冲"用堆叠实现,而不是另起 L4 名号。
- GPU 侧 :NVIDIA Blackwell 的 Context Memory / HBM 侧 KV-cache 层 、Apple M 系列的 片上 SLC(系统级缓存) 也都是"L3 类结构之下、主存之上"的变形。
从大容量存储向下叫分层存储,分在线/近线/离线
| 类别 | 2026 定义 | 2026 典型介质 |
|---|---|---|
| 在线 Online | 通电、挂载、立即可 I/O,TTD 通常 ≤ 80 ms(SNIA Emerald) | 一直转的 HDD、SSD、NVMe、SAN/NAS、低延迟云盘 |
| 近线 Nearline | 不立即可访问,但机器自动上线,无需人 | MAID 盘阵、自动磁带库(机械臂)、**云 Nearline(GCS Nearline / S3 Glacier Instant)、近线 QLC SSD(NL SSD)** |
| 离线 Offline | 必须人工干预才上线 | 手拔磁带、离线光盘、冷备份盘、手动装载的 LTO、Air-gapped 归档 |
内存层级如何制约程序性能
整个计算机体系结构里最经典的矛盾,叫 "内存墙"(Memory Wall)
大多数现代中央处理器(CPU) 的运算速度已经极快,以至于对绝大多数程序负载而言,性能瓶颈 在于内存访问的访问局部性 、CPU 高速缓存的效率,以及存储层级之间的数据传输效率 来源请求。
因此,CPU 大部分时间都处于空闲状态,等待内存 I/O 完成。这有时被称为空间成本 :一个更大的内存对象更有可能溢出 "小而快" 的存储层级,转而需要使用 "大而慢" 的层级。由此产生的内存使用负载被称为压力(分别为寄存器压力、缓存压力和(主)内存压力)。
数据在更高层级缺失、需要从更低层级调取的情况,对应术语分别为:
- 寄存器溢出(由寄存器压力导致:从寄存器溢出到缓存)
- 缓存未命中(从缓存调取到主内存)
- (硬)缺页异常(从真实主内存调取到虚拟内存,即大容量存储;无论实际存储技术是什么,通常都统称为 "磁盘")
现代编程语言 主要默认存在两层内存:主(工作)内存和大容量存储。例外是相对底层的汇编语言 ,以及 C 语言等高级语言中的内联汇编------ 在这些场景下可以使用 "预取" 指令提前加载缓存。
要充分利用内存层次结构,需要程序员、硬件和编译器的协作(同时也需要操作系统的底层支持):
程序员 (Programmer) 文件 I/O、数据布局、并行/线程亲和性
编译器 (Compiler) 寄存器分配、循环变换、prefetch 生成
硬件 (Hardware) Cache 协议、预取器、一致性、DDR/CXL 控制器
操作系统 (OS) 虚拟内存、页表、swap、NUMA/CXL tiering
性能墙与三维数组
通过调换三维数组里三层循环的顺序,你可以让程序从"飞快"变成"极慢",而这背后的原因完全取决于 CPU 缓存和局部性原理。
CPU 缓存之所以能加速程序,靠的是两个规律:
| 类型 | 含义 | 缓存如何利用它 |
|---|---|---|
| 时间局部性 | 刚访问过的数据,很快还会被访问 | 把数据留在缓存里,下次直接用 |
| 空间局部性 | 访问了地址 A,附近的数据很快也会被访问 | 一次加载一整块(Cache Line,通常 64 字节)到缓存 |
什么是 Memory Tiering?
传统上,我们以为"主内存"就是一块均匀的、速度一样的 DDR 内存 。但到 2026 年,这个假设已经不成立了。
Memory Tiering = 把"主内存"按性能分成多个层级,像存储层级一样管理。
为什么需要?
因为现代系统里,"主内存"可能由完全不同的硬件混搭而成:
| 内存类型 | 延迟 | 带宽 | 成本 | 在系统中的角色 |
|---|---|---|---|---|
| 本地 DDR5 | ~80 ns | ~60 GB/s | 高 | Tier 1(快层) |
| CXL 内存(插在 PCIe 槽上) | ~250 ns | ~40 GB/s | 中 | Tier 2(慢层) |
| Optane/3D XPoint(已退场) | ~150 ns | ~低 | 中 | 历史方案 |
| GPU 显存(HBM) | ~10 ns | ~3 TB/s | 极高 | 加速器自有 |
| NUMA 远端内存 | ~140 ns | ~共享 | 同 DDR | 跨 socket |
这些设备都出现在同一个物理地址空间里 ,操作系统看到的"内存"不再是均匀的了。所以需要像管理存储层级一样,把它们分层、迁移、调度。
存储 Tiering(熟悉的):
热数据 → NVMe SSD(快、贵、小)
温数据 → SATA SSD(中)
冷数据 → HDD(慢、便宜、大)内存 Tiering(新的):
热页 → 本地 DDR5(快、贵)
温页 → CXL 内存(中)
冷页 → NVMe(swap,极慢)
Linux 怎么实现 Memory Tiering?
1. 基于 NUMA 扩展
Linux 把每个内存设备看成一个 "CPU-less NUMA node"(没有 CPU 的 NUMA 节点):
传统 NUMA:
Node 0: CPU 0 + 本地 DDR
Node 1: CPU 1 + 本地 DDR
2026 内存 Tiering:
Node 0: CPU 0 + 本地 DDR5 (距离 = 最近)
Node 1: CPU 1 + 本地 DDR5 (距离 = 近)
Node 2: CXL 内存(无 CPU) (距离 = 较远,用"abstract distance"表示)
Node 3: 可能还有另一块 CXL (距离 = 更远)
"abstract distance" :不是物理距离,而是性能距离------延迟越高、距离越大。
2. 用"热页"迁移
Linux 内核通过 page fault 的频率来判断一个内存页是"热"还是"冷":
- 经常被访问的页 → 热 → 迁移到快层(DDR5)
- 很久没被访问的页 → 冷 → 迁移到慢层(CXL 内存)
- 极冷 → swap 到 NVMe
关键人物:
- Huang Ying:Linux 内核内存 Tiering 的主要开发者,他的方案已经合入主线
- Al Maruf 的 TPP(Tiered Page Placement) :学术方案,性能不错,但还没进 Linux 主线
3. 加权交错分配(Weighted-interleave)
新分配内存时,不是"全放最快层"(会很快撑爆),而是按权重交错分配:
DDR5 : CXL = 70 : 30
意思是:新内存 70% 概率放 DDR5,30% 放 CXL。这样快层不会瞬间满,慢层也能被利用。
内存分层是应对"内存墙"挑战的关键技术之一。其核心思路是构建一个由性能优先的DRAM层(如DDR5) 和成本-容量优化的扩展内存层(如CXL内存) 组成的体系。操作系统会根据数据访问频率,自动将不常访问的"冷数据"迁移到扩展层,从而让宝贵的DRAM资源专注于处理"热数据"。这种策略能在保证绝大多数应用性能的同时,有效降低系统的总体内存成本。
放眼当今2026 年
- CXL 3.0 普及:服务器开始插 CXL 内存扩展卡(Samsung CMM-D、Micron CZ120),容量 128GB--1TB/卡,成本约 DDR5 的 40%
- AI 工作负载:模型权重几百 GB,不可能全放 HBM/DDR5,必须分层
- 云厂商在用:AWS、Azure 的某些实例已经用 CXL 做内存池化