你写两个完全独立的变量,CPU0 改一个、CPU1 改另一个,按理互不干扰。但跑起来你会发现,性能比单线程还慢 10 倍——这一切背后藏着一个硬件给出的小数字:64 字节缓存行。
为什么是 64 不是 32 也不是 128?这不是软件的随意选择,而是 DDR SDRAM burst 长度(8 拍)乘以总线宽度(64bit / 8 字节)凑出的天然粒度。一次内存事务恰好填满一行,多搬不浪费、少搬不够用。Intel、AMD、ARM 主流架构全都统一到这个数字。
但当多核世界遇上 64 字节缓存行,就出现了所有性能工程师必须面对的难题——伪共享(False Sharing)。两个本来不相干的变量,只要恰好挤在同一行 64 字节里,硬件就会把整行在多个核心之间反复弹来弹去。MESI 协议下每一次 M ↔ I 的状态切换都是几百个时钟周期。本期视频用一个 8 核 1 亿次累加的 benchmark 给你看真实数字:不加 padding 时每秒 1.2 亿次,加上 ____cacheline_aligned 后每秒 12.4 亿次——10 倍差距,就因为一个 56 字节的 padding 字段。
我们会从一个共享记事本的生活类比切入,画出三级缓存层次(L1/L2/L3 + 主存),讲清楚 MESI 状态机如何让伪共享发生,然后深入 Linux 内核源码看四个真实的化解方案:____cacheline_aligned 宏的 GCC attribute 展开、CONFIG_SMP 条件编译的零开销技巧、struct rq runqueue 的对齐布局、per-CPU 数据如何从源头消除共享、__read_mostly 段如何让只读热数据集中。最后还会教你用 perf c2c 这个鲜为人知的工具线上诊断伪共享热点。
致敬四位推动这一切的关键人物:Linus Torvalds 在 SMP 化早期反复强调"对齐就是性能";Paul McKenney 在《Is Parallel Programming Hard》里把 cacheline 工程化方法论写成教材;Peter Zijlstra 把 spinlock、rwsem 这些每秒数千万次访问的结构精算到字节;Ingo Molnar 让 CFS 调度器和 per-CPU runqueue 在几百核上仍能线性扩展。
本期内容:
- 64 字节这个数字怎么来的:DDR burst × 总线宽度的硬件物理结构
- L1/L2/L3 三级缓存层次:从纳秒级寄存器到百纳秒级主存
- MESI 缓存一致性状态机:Modified/Exclusive/Shared/Invalid 四态转换
- 伪共享的代价:cacheline 在多核间反复弹跳的时序流程
- ____cacheline_aligned 宏的展开:GCC __attribute__((aligned(64))) + CONFIG_SMP 条件编译
- 内核源码实战:runqueue、spinlock、per-CPU 数据三种典型化解方案
- 用 perf c2c 工具线上诊断 false sharing 热点
适合人群:写过高并发服务的后端工程师、Linux 内核学习者、想把多核性能榨干的系统工程师、JVM/Go/Rust 高级开发者、对 CPU 体系结构和缓存一致性协议好奇的朋友。
理解了 64 字节这个数字,你看任何高性能并发代码都会立刻打通任督二脉——为什么 Java 要 @Contended、为什么 Rust 要 repr align、为什么 spinlock 旁边都加一堆看起来没用的 padding。这不是奇技淫巧,是物理边界给软件的硬约束。
#Linux内核 #性能优化 #缓存行 #伪共享 #多核并发 #CPU架构 #FalseSharing #MESI #percpu #cacheline