bigywater.tech
Java · 311

CPU Cache Line:Java 代码如何触发缓存一致性

缓存行有多大?代码怎么写才能跟缓存配合?这篇用 Java 步长遍历、二维数组遍历和随机依赖读,在本机上把缓存行大小和各级缓存容量「测」出来,再和 sysctl 的数字对照。

128 字节
本机(Apple Silicon)的缓存行大小:sysctl 与步长测试一致
4.7 倍
4096×4096 int 矩阵按列遍历相对按行遍历的耗时
1.74 → 105.2 ns
随机依赖读延迟:128 KB 工作集到 256 MB 工作集

缓存参数

实测 · 本机执行输出
  hw.cachelinesize = 128
  hw.l1dcachesize = 65536
  hw.l2cachesize = 4194304
  hw.perflevel0.l1dcachesize = 131072
  hw.perflevel0.l2cachesize = 16777216
  hw.perflevel1.l1dcachesize = 65536
  hw.perflevel1.l2cachesize = 4194304
  hw.perflevel0.logicalcpu = 6
  hw.perflevel1.logicalcpu = 4

步长遍历

实测 · 本机执行输出
  数组 256 MB(int[67108864]);每个步长重复 5 次取最小值;「总时间」是遍历一遍(访问 N/步长 个元素)
  步长     访问元素数        总时间 ms       每次访问 ns     
  1      67108864     40.23        0.599       
  2      33554432     20.24        0.603       
  4      16777216     10.07        0.600       
  8      8388608      4.94         0.588       
  16     4194304      4.42         1.053       
  32     2097152      7.36         3.510       
  64     1048576      4.07         3.880       
  128    524288       2.01         3.828       
  256    262144       0.86         3.266       
  1024   65536        0.23         3.524       
  4096   16384        0.07         4.097

按行与按列

实测 · 本机执行输出
  4096×4096 的 int 矩阵(64 MB):按行遍历(内层是 j)10.1 ms;按列遍历(内层是 i)47.7 ms;比值 4.7 倍

随机依赖读

实测 · 本机执行输出
  工作集大小          随机依赖读 ns/次      
  4 KB           1.72            
  16 KB          1.72            
  32 KB          1.72            
  64 KB          1.73            
  128 KB         1.74            
  256 KB         3.97            
  512 KB         5.02            
  1 MB           5.55            
  2 MB           6.00            
  4 MB           5.94            
  8 MB           7.03            
  16 MB          11.32           
  32 MB          31.64           
  64 MB          70.65           
  256 MB         105.20

分步演示

CPU 缓存行
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,Apple Silicon(6 性能核 + 4 能效核,线程可能在任一种核上运行),自写计时(不是 JMH),取多次重复的最小值
    • 没有验证:x86 与 Linux 的缓存行(通常 64 字节)、硬件预取器对步长结果的影响(没有单独关闭)、TLB 的影响(大步长下可能叠加)、性能核与能效核分别的数字、1 GB 工作集的延迟
    京ICP备2026067502号-1京公网安备11010502063487号