Java-Ram-Cache-Block-Transfer

Cpu 对于可能被多次访的内存区域,会将其复制到 cache 中,之后访问不再从主存中获取,提升效率。从 ram 到 cache 的复制过程(Block Transfer),复制单位为 linesize ,此处为 64 byte。[1]

请看如下代码段,1 与 2 所需时间差不多,甚至 2 有时时间比 1 还长 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// int : 4 byte
// cache line : 64 byte
int[] arr = new int[1 << 26];

// 1
long t1 = System.currentTimeMillis();
for (int i = 0; i < arr.length; i++) arr[i] *= 3;
System.out.println(System.currentTimeMillis() - t1 + " ms");

// 2
long t2 = System.currentTimeMillis();
for (int i = 0; i < arr.length; i += 2) arr[i] *= 3;
System.out.println(System.currentTimeMillis() - t2 + " ms");


// 3
long t3 = System.currentTimeMillis();
for (int i = 0; i < arr.length; i += 32) arr[i] *= 3;
System.out.println(System.currentTimeMillis() - t3 + " ms");

1 与 2 Block transfer 次数相同,时间不会差太多[2]

3 相比于 1 和 2 Block transfer 少了一倍,时间与其相差略小于一倍[3]


  1. Intel’s Optimization Reference Manual is the vendor reference for cache and memory-access optimization; the common 64-byte cache-line model is a platform assumption, while JLS SE 21 §4.2.1 defines Java int as 32-bit. ↩︎

  2. Intel’s Optimization Reference Manual treats cache locality and memory access as platform performance concerns; in a contiguous int[] model, i++ and i += 2 can touch nearly the same cache-line set even though one loop updates fewer elements. Java object/array layout should be checked with JOL when exact layout matters. ↩︎

  3. Large stride access can reduce touched cache lines, but the measured ratio is not guaranteed: prefetching, JVM layout, JIT compilation, memory bandwidth, and timer noise all matter, so Java microbenchmarks should use JMH or equivalent measurement. ↩︎