为什么long和double在Java类的常量池中占用两个条目?

xea*_*xea 6 java jvm constants .class-file

Java虚拟机规范规定,8字节(如longdouble)常量占用两个条目在constant_pool表中,不同于占用每个只有一个入口其他常量.该规范还提到它是一个糟糕的选择,但没有解释原因.

这个设计决定背后的原因是什么?当时的好处是什么?

Ant*_*ony 3

一个明确的答案需要与参与 Java 早期开发的人员交谈。然而,我认为很明显,字节码格式最初设计时考虑的是简单解释器的性能。

考虑一下如何编写一个非常简单的 Java 字节码解释器。没有 JIT,没有优化等。您只需执行每条指令即可。假设常量池在加载时已被解码为 32 位值的表,像 ldc2_w x 这样引用常量池的指令将沿着以下行执行 C 代码

*(*int64)(stack_ptr += 8) = *(*int64)(constant_pool_ptr + x * 4)

基本上,如果您使用的是 32 位计算机,并且将所有内容转换为原始指针访问而不进行优化,那么使用两个插槽来存储 64 位值就是实现事物的逻辑方法。

今天它是一个糟糕的选择,因为现在的口译员并没有像这样完全没有优化。事实上,代码通常是 JIT 的。此外,64 位平台是常态,这意味着引用类型无论如何都会占用 64 位*,即使规范将它们视为 32 位值。因此,这种黑客行为不再有任何好处,但我们仍然付出规范和实现复杂性的代价。

^ 至少理论上是这样。即使在 64 位平台上,JVM 默认也使用 32 位压缩指针,以减少内存使用。