Java 对象[] 和缓存跨度

Java Object[] and cache strading

正如我们所知,当内存移动到 cpu 上的 L 个缓存时,它会与缓存行一起移动,因此整个缓存分级性能优化...

好吧,在 java 中,当我们定义一个数组时,jmm 保证每个元素的内存将按顺序分配。但是,如果我们有引用数组,这些引用可以随机指向内存中的不同位置。

我的问题是 java 是否按顺序分配实际对象内存?我们为此做了哪些优化?

例如,如果我们声明 int[],我们确信它们在内存中实际上都是连续的,但是如果我们定义一个 NewType(如结构),其中有两个 int 字段,并声明 NewType[] 将 java 找出并按顺序保留实际内存?

My question is does java allocate actual objects memory sequentially?

这并不能保证,但大多数时候 OpenJDK/Oracle JVM 可以。有些时候不是这样;

  • 当您在永久 space,
  • 中分配一个大对象时
  • 您的 TLAB 已满,您需要再买一个。

然而,在 TLAB 中,它只是在内存中顺序分配。

declare NewType[] will java figure out and keep actual memory sequentially or not?

Java 没有弄清楚任何事情,也没有按照它的方式在内存中随机分配对象。通常,每个 new 个对象将紧跟在最后一个之后。

but if we define a NewType (like struct) that has two int fields in it, and declare NewType[] will java figure out and keep actual memory sequentially or not?

在这种情况下 java 对缓存不是很友好,因为除了原始类型 java 数组不是压缩数据结构,它们是指向内存中其他地方分配的对象的引用数组。

即从数组到对象本身至少有一个间接级别。这个问题通常被称为 "pointer chasing".

即通常内存布局如下所示:

HlRRRRRRRRRRRRRRRRRRRRRRRRR0HR0iii0HR0iii0HR0iii0HR0iii0HR0iii0HR0iii0HR0iii0
         Array             | Obj  | Obj  | Obj  | Obj  | Obj  | Obj  | Obj  |

H = object header
l = array length
R = reference
i = int
0 = various types of padding

您可以使用jol检查对象的内存布局。

JDK 开发人员正在研究 Value types as part of project valhalla that will eventually allow packed arrays to exist, which may be needed as part of project panama,但这仍然是遥远的未来。

同时还有旨在提供类似功能的第 3 方项目:

其他项目要么使用堆外存储(例如通过 sun.misc.Unsafe),要么使用 ByteBuffer / byte[] 数组的视图来创建打包的、缓存友好的数据结构,但代价是更复杂API。