整数数组如何在JVM内部存储?

izb*_*izb 5 java jvm

java中的一组int作为32位值的块存储在内存中.如何存储整数对象数组?即

int[] vs. Integer[]
Run Code Online (Sandbox Code Playgroud)

我想,Integer数组中的每个元素都是对Integer对象的引用,并且Integer对象具有对象存储开销,就像任何其他对象一样.

但是我希望JVM能够在整个引擎中做一些神奇的聪明才智,因为整数是不可变的并且存储它就像一组int.

我的希望是天真的吗?在每个最后一盎司性能都很重要的应用程序中,Integer数组是否比int数组慢得多?

ral*_*lfs 12

我知道没有VM会存储一个类似int []数组的Integer []数组,原因如下:

  1. 数组中可以有null的 Integer对象,并且没有剩下的位用于在int数组中指示它.VM可以将每个阵列插槽中的这1位信息存储在hiden位阵列中.
  2. 您可以在Integer数组的元素中进行同步.作为第一点,这很难克服,因为您必须为每个阵列插槽存储一个监视器对象.
  3. 可以比较Integer []的元素的身份.例如,您可以通过new创建值为1的两个Integer对象,并将它们存储在不同的数组槽中,然后检索它们并通过==进行比较.这必然会导致错误,因此您必须将此信息存储在某处.或者你在某处保留对其中一个Integer对象的引用,并使用它进行比较,你必须确保其中一个==比较是假的,一个是真的.这意味着对于优化的 Integer数组,对象标识的整个概念很难处理.
  4. 您可以将Integer []转换为例如Object []并将其传递给期望只有Object []的方法.这意味着处理Object []的所有代码现在也必须能够处理特殊的Integer []对象,使其变得越来越慢.

考虑到所有这些因素,它很可能是可能使一个特殊的整数节省相比于一些空间[] 天真的实现,但额外的复杂性可能会影响到很多其他的代码,使得它到底慢.

使用Integer []而不是int []的开销在空间和时间上都可以很大.在典型的32位VM上,Integer对象将消耗16个字节(对象头为8个字节,有效负载为4个,对齐为4个额外字节),而Integer []使用的空间与int []相同.在64位VM中(使用64位指针,并非总是如此),Integer对象将消耗24个字节(标头为16,有效负载为4,对齐为4).另外,Integer []中的一个插槽将使用8个字节而不是int []中的4个字节.这意味着您可以预期每个插槽的开销为16到28个字节,与普通的int数组相比,这是4到7倍.

性能开销也很大,主要有两个原因:

  1. 由于使用了更多内存,因此对内存子系统施加了更大的压力,使其在Integer []的情况下更容易出现缓存未命中.例如,如果以线性方式遍历int []的内容,则缓存将在您需要时已经获取大部分条目(因为布局也是线性的).但是在Integer数组的情况下,Integer对象本身可能会在堆中随机分散,这使得缓存难以猜测下一个内存引用将指向的位置.
  2. 垃圾收集必须做更多的工作,因为使用了额外的内存,因为它必须单独扫描和移动每个Integer对象,而在int []的情况下,它只是一个对象,而对象的内容不是必须被扫描(它们不包含对其他对象的引用).

总而言之,在性能关键工作中使用int []将比在当前VM中使用Integer数组更快且内存效率更高,并且在不久的将来这种情况不会发生太大变化.