为什么long和double在Java类中占用两个条目'恒定池?

时间:2016-10-15 13:01:07

标签: java jvm constants .class-file

Java Virtual Machine Specification表明8字节(例如longdouble)常量占用constant_pool表中的两个条目,不同于仅占用其他常量每个一个条目。该规范还提到它是一个糟糕的选择,但没有解释原因。

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

3 个答案:

答案 0 :(得分:2)

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

考虑如何编写一个非常简单的Java字节码插件。没有JIT,没有优化等。您只需在执行时执行每条指令。假设在加载时已将常量池解码为32位值的表,则引用常量池的指令(如ldc2_w x)将沿着

行执行C代码。

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

基本上,如果您使用的是32位计算机,并且正在将所有内容转换为原始指针访问而不进行优化,那么使用两个插槽来获取64位值只是实现目标的合理方式。

今天选择不好的原因是因为现在,口译员并没有像这样完全没有优化。实际上,代码通常是JITed。此外,64位平台是常态,这意味着参考类型无论如何都需要64位*,即使规范将它们视为32位值。因此,这种攻击不再有任何好处,但我们仍然需要支付规范和实现复杂性的成本。

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

答案 1 :(得分:0)

我不知道实际的答案,没有参与Java及其虚拟机的设计。我可以做出有根据的猜测。

常量池数组中充满了指向其他项的项;如果已指向长和双常数而不是包含在数组中,那么他们就不需要占用额外的空间。

由于它们确实占用了一个额外的索引,这意味着必须测试数组中的每个索引,以确定它是否是“不可用的”#39;索引后的索引为long或double。与仅检查范围相比,这会减慢对数组所有元素的访问速度。

从软件工程的角度来看,使用数组也是一种不自然的方式。对这个结构的每一个引用都需要包含关于这些索引的注释,以免一些额外的代码假设数组每个元素具有一个常量大小(这是关于数组的一个自然假设)。

进一步猜测,可能有人认为占用空间指向一个只需要更多空间的结构是一种耻辱,因此通过将其包含在数组本身中来节省空间。他们甚至可能认为这是使用长值和双值的一种更有效的方式,而忽略了它减慢其他一切的事实。

答案 2 :(得分:0)

他们使用了2,因为他们在设计时决定了这一点。没有理由它必须是2.没有理由它不是8字节的8。尽管引用可能是64位,但引用始终为1。

当时有意义的是将32位的所有内容都视为32位并且假设参考是32位这么长而双倍是双倍但是如果它是虚拟机它不会很重要。

两种方式的表现差异完全是名义上的。

  

规范还提到这是一个糟糕的选择,但没有解释原因。

在后面看来,最简单的事情就是让它成为一切插槽,而不是参与如何在运行时使用内存。注意:JVM可以优化掉变量,因此它们根本不占用任何空间。