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

时间:2008-09-16 20:23:02

标签: java jvm

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

int[] vs. Integer[]

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

我希望JVM在整个引擎中做一些神奇的聪明,因为整数是不可变的,并且就像一个整数数组一样存储它。

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

5 个答案:

答案 0 :(得分:11)

我知道没有VM会将int []数组存储为Integer []数组,原因如下:

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

    使用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 []的情况下,它只是一个对象和对象的内容不必扫描(它们不包含对其他对象的引用)。
    3. 总而言之,在性能关键工作中使用int []将比在当前VM中使用Integer数组更快且内存效率更高,并且在不久的将来这种情况不会发生太大变化。

答案 1 :(得分:3)

John Rose在JVM中fixnums工作以解决此问题。

答案 2 :(得分:1)

我认为你的希望非常天真。具体来说,它需要处理Integer可能为null的问题,而int不能。仅这一点就足以存储对象指针。

也就是说,实际的对象指针将是一个不可变的int实例,特别是对于一个选择的整数子集。

答案 3 :(得分:0)

它不会慢得多,但因为Integer []必须接受“null”作为条目而int []不必,所以会涉及一些书记,即使Integer []是由int []支持。

因此,如果每一次性能都很重要,那么用户int []

答案 4 :(得分:0)

Integer可以为null,而int不能的原因是因为Integer是一个成熟的Java对象,包含所有开销。因为你可以写

,所以有价值
Integer foo = new Integer();
foo = null; 

这对于说foo会有一个值有好处,但它还没有。

另一个区别是int不执行溢出计算。例如,

int bar = Integer.MAX_VALUE;
bar++;

会快乐地增加条形,你最终得到一个非常负数,这可能不是你想要的第一个。

foo = Integer.MAX_VALUE;
foo++;

会抱怨,我认为这会是更好的行为。

最后一点是,作为Java对象的Integer带有对象的空间开销。我认为其他人可能需要在这里加入,但我相信每个对象消耗12个字节用于开销,然后用于数据存储本身的空间。如果你追求性能和空间,我想知道Integer是否是正确的解决方案。