CPU 缓存的命中与否,往往比算法复杂度更早决定一段代码的真实耗时。本文围绕多级缓存的结构、Cache Line 的映射方式与多核一致性协议展开,再用五个代码示例说明它们如何变成可感知的性能差异,并顺带更正几处流传甚广的参数与概括。
多级缓存:速度、容量与共享的权衡
现代 CPU 一般都有 L1、L2、L3 三级缓存 [9,10,12]。L1 与核心最接近,因此最快,但容量最小 [12,16];它进一步分成指令缓存和数据缓存 [9,10,12,44]。L1 和 L2 通常为每个核心私有 [9,15],L3 由多个核心共享 [9,15,16],现代系统中 L2、L3 一般也集成在处理器 die 上 [15]。例外总是存在:Alder Lake(第 12 代酷睿)的 E 核按 4 个一组共享 2MB 二级缓存,而不是每核私有 [44]。
缓存访问速度与容量成反比。素材引用的 L1 4 周期、L2 11 周期、L3 39 周期、RAM 107 周期 [9] 是常见参考值,但并非普适——不同资料给出的范围是 L1 约 2~4 周期 [10](有的设计可到 1 周期 [16])、L2 约 10~20 周期 [11]。量级上的差距是确定的:DRAM 靠电容存储电荷、需要定时刷新才能保住数据 [9],而 L1 供数效率可达 98%、RAM 只有约 2% [15]。
为什么不直接做一块又大又快的缓存?因为容量越大晶体管越多,信号路径越长,速度反而下降;L1 之所以最快,正因为它紧贴核心、信号路径最短 [12]。分级的价值在于让数据尽量停留在离 CPU 近的层级,减少访问慢速主存的次数 [10,11]。
素材用 Intel Core i7-8700K 举例:它是 2017 年 10 月发布的 6 核 12 线程处理器 [3,4],每核 L1 64KB(数据、指令各 32KB)、L2 256KB [3]——这些都没错;但素材称其 L3 为 2MB 有误,官方规格与多个来源均为共享 12MB [3,4,5,7]。作为参考,主流处理器 L3 容量从 2MB 到 96MB 以上不等 [16]。
Cache Line 与组相联:地址如何装进缓存
CPU 不会按字节搬运数据,而是以 Cache Line 为最小单位加载和同步 [69],主流大小通常为 64 字节 [69](正好 16 个 32 位整数),缓存的替换也以 Cache Line 为单位 [53]。
缓存远小于内存,必须决定内存块放在哪个缓存位置,这就是放置策略 [63]。最简单的做法是对缓存行数取模,但取模后多个内存块会映射到同一个缓存块,产生块冲突 [53];全相联(任何位置都能放)则使查找退化为线性扫描。组相联是折中:把若干 Cache Line 绑成一组,先用地址的中间位定位组,再在组内做小范围匹配 [63]。素材以”32KB、8-Way、64B”为例推导出:共 512 条 Cache Line、64 组、每组 8 条,于是间隔恰好 4096 字节的地址会竞争同一组——这就是缓存冲突 [53]。
但请注意,这组参数不应被当作”Intel 的普遍配置”:至少从 Ice Lake 起,Intel 的 L1 数据缓存已达 48KB [49];12 代 Alder Lake 的 P 核 L1 数据为 48KB、12-Way 组相联 [44],指令为 32KB [43,44]。也就是说,“32KB、8-Way”只是特定世代的值,容量和相联度随架构变化 [44,49],冲突发生的间隔也要按具体 CPU 的组数重算 [44,53]。
硬件预取会缓解一部分问题:缓存会学习并预测访问模式,对连续线性访问提前取数 [17]。
缓存一致性:现代 CPU 并不靠广播总线
多核共享数据时,一个核心更新了某变量,其他核心的副本必须随之失效或更新,这就是一致性问题 [9]。写策略上,有 write-through(同时写缓存和内存)与 write-back(只写缓存、稍后刷回)两种 [9]。
素材介绍了 Directory 与 Snoopy 两类方案,但结论”现在基本都是使用 Snoopy 总线”并不准确。Snoopy 依赖把请求广播给所有核 [24],广播在超过 2~4 个核心后扩展性就很差 [28];Directory 走点对点消息、扩展性更好 [24]。现代多核 CPU 的实际做法是两者结合:Intel 在 Skylake 服务器上实现了分布式共享的 Snoop Filter,它本质是一个目录,跟踪所有核 L1/L2 中缓存行的位置与状态 [22,28]。snoop filter 监视一致性流量、记录哪些缓存持有副本,从而避免向无关缓存广播 [30]。更直白地说,现代 CPU 的 MESI 状态是靠消息加 snoop filter(本质是目录)来维护的,Intel(MESIF)和 AMD(MOESI)实际都是这么做 [23]。
状态协议层面,MESI 是最基础的四种状态:Modified(已修改)、Exclusive(独占)、Shared(共享)、Invalid(无效)[31,64,66]。它采用写失效方式:写共享数据时向所有缓存发出失效通知 [24]。
MESI 的问题在于:数据更新后其他副本被标 Invalid,别的核再读就要回到内存取,而缓存间直接传数据要快得多 [35]。于是有了两个扩展方向:
- MOESI 增加 Owner 状态 [31,38]。O 状态的缓存是共享数据的宿主,且数据是 dirty 的(尚未写回内存)[31,38],其他核 miss 时可以直接从它取数,减少写回内存的次数 [31,38]。AMD64 文档采用的就是 MOESI [31],它也用于 AMD Opteron 及部分 ARM 核 [37]。
- MESIF 增加 Forward 状态 [35,38]。F 缓存负责响应共享数据的请求,让至多一个缓存应答,从而减少一致性流量 [39]。MESIF 是 Intel 为 QuickPath Interconnect(QPI)这类点对点互连设计的 [35,36,37]。F 与 O 的意图不同:O 持有的是 dirty 数据,F 持有的是 clean 数据,可以丢弃而无需另行通知 [38]。
因此”AMD 用 MOESI、Intel 用 MESIF”是个过于简单的概括:MESIF 用于 Intel 的 QPI 系统 [35,37],而 F 状态并不存在于核心内部,核内的行保持 MESI 状态 [34]。更准确的说法是:用哪个协议取决于互连与缓存层次,且现代 Intel/AMD 都通过 snoop filter 一类目录结构来跟踪这些状态 [23]。
五个代码示例:缓存如何决定性能
示例一:步长 2 还是 8,几乎没差别。 遍历 64M 个整数的数组,步长 2 与步长 8 的计算量差 4 倍,但作者实测两者时间几乎相同。原因就是加载以 64 字节(16 个 32 位整数)的 Cache Line 为单位 [69]:两种步长访问到的都是同一批 Cache Line,需要从内存搬上来的行数没有区别。
示例二:步长撞上同一组,性能骤降。 以固定步长扫描数组,当步长乘 4 字节恰好等于 4096(素材机器的组数乘 Cache Line 大小)时,访问地址的组号不变,全部竞争同一组,冲突导致时间陡增 [53]。参数随 CPU 而变:换到 12-Way 的现代处理器,触发冲突的步长和激烈程度都会不同 [44,53]。
示例三:二维数组按行还是按列遍历。 两种写法寻址和计算量相同,但作者实测逐列遍历慢得多。逐行遍历顺序访问连续地址,加载进来的 Cache Line 全部用上;逐列遍历每走一步就跳到下一行,刚加载的行数据大多浪费,命中率天差地别 [69]。
示例四:两个线程写同一 Cache Line 的不同元素。 p[0] 与 p[1] 相邻,位于同一条 Cache Line;p[0] 与 p[30] 则必然不在。两个线程各写各的元素,逻辑上无冲突,但一致性同步以 Cache Line 为单位 [69]:写 p[1] 会令 p[0] 所在行在其他核的副本失效,缓存行在两个核之间来回同步,作者实测前者比后者慢数倍 [64,66,69]。
示例五:伪共享让多线程反而不如单线程。 用多个线程分别统计数组片段,把结果写进 result[id]。这些元素挤在同一条 Cache Line 上,每个线程写自己的元素都会触发整行失效与重同步,作者实测 6 个线程跑不过 1 个线程 [64,66,69]。解法有两个方向:一是让每个线程在局部变量里累计、最后写回一次;二是对共享结构做缓存行填充/对齐,让不同线程访问的元素落在不同的 Cache Line 上 [64,66,69]。
原文更正:素材称 Intel Core i7-8700K 的 L3 为 2MB,实际为 12MB。 [3]
参考来源
- Intel
- Investor Relations :: Intel Corporation (INTC)
- Intel Core i7-8700K Specs | TechPowerUp CPU Database
- Intel Core i7-8700K Guide: Is It Still Viable Today?
- Leaked Intel i7 8700K specifications - OC3D
- Intel Coffee Lake Core i7-8700K 6 Core, 95W TDP Processor Leaks Out
- Intel® Core™ i7-8700 Processor
- Amazon.com: Intel Core i7-8700K Desktop Processor 6 Cores up to 4.7GHz Turbo Unlocked LGA1151 300 Series 95W : Electronics
- CPU 是如何与内存交互的? - luozhiyun`s Blog
- 天啦噜!知道硬盘很慢,但没想到比 CPU L1 Cache 慢 10000000 倍 - 小林coding - 博客园
- *L2快取: 通常為各個core專屬的備援快取,延遲僅次於L1,約為10-20個時脈週期,速度雖然比L1慢,但也比DRAM快約25倍。 主要任務是當 L1發生Cache Miss時,用來攔截L1找不到的資料請求,立刻提供後備資料,減少向外層尋找的時間。與L1不同,L2的指令與資料混合存放。容量約為1-3MB。 講一下Cache miss,是指CPU在執行運算時,需要讀取某個記憶體位址的資料或指令,但發現該資料並不在快取中的狀況。當Cache Miss發生時,CPU 必須暫停運算,並向下一層較慢的記憶體去抓取資料,例如從 L1找 L2,甚至一路找到外部的DRAM。 *L3快取: 通常作為整個晶片或pod共享的資源池,核心目標是努力攔截資料請求,減少處理器向外部主記憶體DRAM發起高延遲存取的次數,可以說是最後一道防線。(續)
- CPU cache - Wikipedia
- CPU性能和CACHE | plantegg
- 操作系统(十三)——CPU Cache_内存访问所需时间-CSDN博客
- CPU cache | Computer Science | Research Starters | EBSCO Research
- The Cache Clash: L1, L2, and L3 in CPUs
- What Is CPU Cache? Guide to L1, L2 & L3 Performance – ACEMAGIC
- What Is A CPU Cache? L1, L2, L3 Explained — 2026 Guide
- 10–20 ns 🔵 RAM: Slower than cache 🟢 SSD: ~50–100 µs …
- CPU cache, why do we typically see larger numbers of L3 …
- Arm CoreLink CCI-500 Cache Coherent Interconnect Technical Reference Manual r1p0
- Directory Structure in Skylake Server CPUs
- computer science - What cache coherence solution do modern x86 CPUs use? - Stack Overflow
- Lecture 18: Snooping vs. Directory Based Coherency
- Snoop Filters in Coherent NoC Systems: Types, Trade‑Offs, & Directory-Based Design - Arteris
- [PDF] Lecture 11 Thread Level Parallelism (4) | NVIDIA
- Snooping-based Cache Coherency Protocol
- Directory Structure in Skylake Server CPUs
- An Introduction to Multiprocessor Systems - Page 5 of 6 - Real World Tech
- Bus snooping - Wikipedia
- 缓存一致性协议 - 杰哥的知识库
- 服务器多核处理器Cache一致性协议
- 面向多核处理器的可配置缓存一致性协议设计与实现
- 英特尔和AMD使用哪种高速缓存一致性协议?-腾讯云开发者社区
- [PDF] MESIF: A Two-Hop Cache Coherency Protocol for Point-to-Point …
- MESIF Cache Coherence Protocol
- Demystifying Cache Coherency in Modern Multiprocessor Systems
- MESIF protocol - Wikipedia
- Why do we need the MOESI/MESIF protocols?
- Practical Cache Coherence - Yizhou Shan’s Home Page
- Zen 4架构L2缓存容量将翻倍,被认为是对抗Alder Lake的关键
- 这篇CPU Cache,绝对没几个人看
- Alder Lake - Wikipedia
- IA Cores Level 1 and Level 2 Caches - 001 - ID:655258 | 12th Generation Intel® Core™ Processors Datasheet, Volume 1 of 2
- Alder Lake S:概述和技术文档
- Alder Lake S: Overview and Technical Documentation
- Going Armchair Quarterback on Golden Cove’s Caches
- Cache sizes getting smaller (some, i.e. L1; though not per core-cache) for AMD (unlike for Apple), for multi-threading? - Offtopic - Julia Programming Language
- CPU cache
- IA Cores Level 1 and Level 2 Caches - 001 - ID:655258 | 12th Generation …
- L2 Stacked Cache?! How AMD’s New CPUs Will Be INSANELY Fast
- CPU 缓存一致性与内存屏障 - beihai blog
- 一文搞懂cpu cache工作原理
- CPU缓存 - 维基百科,自由的百科全书
- CPU体系结构之cache | Ivanzz
- Cache简介 | Official documents
- CPU Cache:访存速度是如何大幅提升的?-编程高手必学的内存知识
- Cache and Memory Hierarchy
- Understanding CPU Cache Organization and Structure
- Cache Memory Fundamentals and Advanced …
- CSC2/452 Computer Organization Caches and the …
- Cache Memory in Computer Organization
- Cache placement policies
- 击穿Java 高并发性能瓶颈:伪共享底层原理、缓存行填充与 …
- MESI 协议
- CPU中的缓存、缓存一致性、伪共享和缓存行填充
- C++ 性能优化必知:CPU 缓存与伪共享避免实战指南
- CPU高速缓存与极性代码设计
- 高并发之伪共享和缓存行填充(缓存行对齐)(@Contended) 原创