35

我读过的关于这个主题的许多书籍/文章,以及我使用“不安全”编写的一个小程序,都表明 Java 中的一维数组在内存中总是连续的。那么它是由 JLS 规定的,还是一种实现约定?询问该问题以确认该指示。

4

4 回答 4

28

不,JVM 规范没有任何此类保证: http ://docs.oracle.com/javase/specs/jvms/se5.0/html/Concepts.doc.html#16446

在实践中可能是这种情况,但您也不能保证字的大小。

Unsafe 不是标准的 Java 类,所以如果你的程序使用它,那么它无论如何都不能移植......

于 2012-04-19T09:09:27.000 回答
15

我想用Java 语言规范、Java SE 8 版 (JLS)Java 虚拟机规范、Java SE 8 版 (JVMS)的说法来刷新这个问题。

我们必须选择回答这个问题:

  1. 对 JVM 实现施加了哪些限制。这是最可靠的方法,因为任何规范的实现固有地假定“所有不被禁止的东西都是允许的”原则。
  2. 大多数 JVM 实现的建议是合理的。

我将指出规范约束。

如果我们查看第 10 章JLS 的数组(以及 JLS 和 JVMS 中与数组相关的任何其他章节),我们找不到任何关于强加给数组的内存布局约束的内容。因此,这绝对意味着数组可能不连续。

此外,JLS 说数组是对象:

第 10 章数组。

在 Java 编程语言中,数组是对象(第 4.3.1 节),是动态创建的,并且可以分配给 Object 类型的变量(第 4.3.2 节)。Object 类的所有方法都可以在数组上调用。...

4.3.1。对象。

对象是类实例或数组。(并且数组是对象)

同时 JVMS 说对象和数组存储在堆上:

2.5.3. 堆

Java 虚拟机有一个在所有 Java 虚拟机线程之间共享的堆。堆是为所有类实例和数组分配内存的运行时数据区域。

但是 JVMS 并不强制堆内存是连续的:

2.5.3. 堆

...堆的内存不需要是连续的。

由于所有数组都存储在堆中并且堆可能不连续,因此数组也可能不连续。

于 2015-07-25T08:50:17.593 回答
11

由于在 Java 中没有与内存地址交互的真正方法,因此规范中也没有定义对象在内存中的布局如何。

请注意,Unsafe几乎自动使用意味着您在规范范围之外漫步。

话虽如此,我敢肯定大多数 JVM 实现实际上确实对(一维)数组使用了线性布局。

于 2012-04-19T09:09:22.020 回答
7

鉴于许多 JVM 要求堆在内存中是连续的,我认为他们不太可能将一维基元数组放置在内存中的不同位置。

Object[] 引用的对象在内存中不太可能是连续的,即使它们是连续的,也可以在没有警告的情况下重新排列。

注意:使用 Unsafe,您可以将数组中的引用作为int值读取,以查看它们在 GC 之前和之后是什么。一些 JVM 使用需要很长的 64 位引用,但大多数使用 32-bti 引用(即使对于 64 位 JVM)

于 2012-04-19T09:14:35.607 回答