Java 中的整数数组在内存中存储为 32 位值 block 。 Integer 对象数组是如何存储的?即
int[] vs. Integer[]
我想象 Integer 数组中的每个元素都是对 Integer 对象的引用,并且 Integer 对象有对象存储开销,就像任何其他对象一样。
但是我希望 JVM 在幕后做一些神奇的聪明事,因为整数是不可变的,并且像存储整数数组一样存储它。
我的希望太天真了吗?在每一滴性能都很重要的应用程序中,整数数组是否比 int 数组慢得多?
最佳答案
据我所知,没有 VM 会像存储 int[] 数组那样存储 Integer[] 数组,原因如下:
- 数组中可以有 null Integer 对象,并且您没有剩余的位来在 int 数组中指示它。不过,VM 可以将每个数组插槽的 1 位信息存储在隐藏的位数组中。
- 您可以同步整数数组的元素。作为第一点,这更难克服,因为您必须为每个数组槽存储一个监视器对象。
- 可以比较 Integer[] 的元素的同一性。例如,您可以通过 new 创建两个值为 1 的 Integer 对象,并将它们存储在不同的数组槽中,稍后您可以检索它们并通过 == 比较它们。这一定会导致错误,因此您必须将此信息存储在某个地方。或者您在某处保留对 Integer 对象之一的引用并使用它进行比较,您必须确保 == 比较之一为假,一个为真。这意味着对象标识的整个概念对于优化整数数组来说很难处理。
- 您可以将 Integer[] 转换为例如Object[] 并将其传递给只需要 Object[] 的方法。这意味着所有处理 Object[] 的代码现在也必须能够处理特殊的 Integer[] 对象,从而使它变得更慢和更大。
考虑到所有这些,可能会制作一个特殊的 Integer[],与 naive 实现相比,它可以节省一些空间,但额外的复杂性可能会影响很多其他代码,最终使它变慢。
使用 Integer[] 而不是 int[] 的开销在空间和时间上可能非常大。在典型的 32 位 VM 上,一个 Integer 对象将占用 16 个字节(8 个字节用于对象 header ,4 个字节用于有效负载,另外 4 个字节用于对齐),而 Integer[] 使用与 int[] 一样多的空间。在 64 位 VM 中(使用 64 位指针,情况并非总是如此),一个 Integer 对象将占用 24 个字节(16 个用于 header ,4 个用于有效负载,4 个用于对齐)。此外,Integer[] 中的槽将使用 8 个字节而不是 int[] 中的 4 个字节。这意味着您预计每个槽的开销为 16 到 28 字节,与普通 int 数组相比,这是一个4 到 7 倍。
性能开销也可能很大,主要有两个原因:
- 由于您使用了更多的内存,因此您对内存子系统施加了更大的压力,使其在 Integer[] 的情况下更有可能出现缓存未命中。例如,如果您以线性方式遍历 int[] 的内容,缓存将在您需要时已经获取大部分条目(因为布局也是线性的)。但是对于 Integer 数组,Integer 对象本身可能随机散布在堆中,这使得缓存很难猜测下一个内存引用将指向何处。
- 垃圾回收必须做更多的工作,因为使用了额外的内存,而且它必须单独扫描和移动每个 Integer 对象,而在 int[] 的情况下,它只是一个对象和对象的内容不必扫描(它们不包含对其他对象的引用)。
总而言之,在性能关键型工作中使用 int[] 比在当前 VM 中使用 Integer 数组更快且内存效率更高,而且在不久的将来这种情况不太可能发生太大变化。
关于java - 整数数组是如何在 JVM 内部存储的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76549/