整数数组如何在JVM内部存储?
java中的一个int数组作为一个32位值块存储在内存中。如何存储整数对象数组? IE。
int[] vs. Integer[]
我以为Integer数组中的每个元素都是对Integer对象的引用,并且Integer对象与其他任何对象一样都具有对象存储开销。
但是,我希望JVM能够在底层实现一些神奇的功能,因为Integer是不可变的,并且像整数数组一样存储它。
我的希望真是天真吗?在性能至关重要的应用程序中,整数数组是否比整数数组要慢得多?
解决方案
回答
我认为希望真是幼稚。具体来说,它需要处理Integer可能为null,而int不能为null的问题。仅此一个原因就足以存储对象指针。
也就是说,实际的对象指针将指向不变的int实例,尤其是对于整数的选定子集。
回答
这不会慢很多,但是因为Integer []必须接受" null"作为条目,而int []不必这样做,所以即使Integer []得到了支持,也会涉及一些记账工作。 int []。
因此,如果每时每刻的性能都很重要,则用户int []
回答
Integer可以为null,而int不能为null的原因是,因为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是否是正确的解决方案。
回答
John Rose在JVM中使用fixnums来解决此问题。
回答
我所知没有VM会像int []数组那样存储Integer []数组,原因如下:
- 数组中可以有空的Integer对象,并且在int数组中没有剩余的用于指示此内容的位。 VM可以将每个阵列插槽的1位信息存储在隐藏位数组中。
- 我们可以在Integer数组的元素中进行同步。首先,这很难克服,因为我们必须为每个阵列插槽存储一个监视对象。
- 可以比较Integer []的元素的身份。例如,我们可以通过new创建两个值为1的Integer对象,并将它们存储在不同的数组插槽中,然后检索它们并通过==比较它们。这必须导致错误,因此我们必须将此信息存储在某处。或者,我们在某处保留对一个Integer对象的引用,并使用该引用进行比较,并且必须确保==比较之一为false,一个为true。这意味着对于优化的Integer数组,对象标识的整个概念很难处理。
- 我们可以将Integer []强制转换为Object []并将其传递给只需要Object []的方法。这意味着所有处理Object []的代码现在也必须能够处理特殊的Integer []对象,从而使其变慢和变大。
考虑到所有这些因素,可能有可能制作一个特殊的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倍。
性能开销也可能很重要,主要有两个原因:
- 由于使用了更多的内存,因此给内存子系统带来了更大的压力,在Integer []的情况下,它更有可能发生高速缓存未命中。例如,如果我们以线性方式遍历int []的内容,则高速缓存将在需要时已提取大多数条目(因为布局也是线性的)。但是在使用Integer数组的情况下,Integer对象本身可能会随机分散在堆中,这使缓存很难猜测下一个内存引用将指向的位置。
- 由于使用了额外的内存,垃圾收集不得不做更多的工作,并且必须分别扫描和移动每个Integer对象,而对于int []来说,它只是一个对象,而对象的内容则没有必须进行扫描(它们不包含对其他对象的引用)。
综上所述,与在当前VM中使用Integer阵列相比,在对性能至关重要的工作中使用int []既会更快,又会提高内存效率,并且在不久的将来这不太可能会发生很大变化。