为什么我不能创build一个大尺寸的数组?

为什么不可能用max int size创build一个数组?

int i = 2147483647; int[] array = new int[i]; 

我find了这个解释:

Java数组通过32位整数进行访问,导致最大理论数组大小为2147483647个元素。

但正如你所看到的我的代码不起作用。 创build大小的数组也是不可能的

 new int[Integer.MAX_VALUE - 5]; 

技术细节

  • 64位HotSpot JVM
  • OSX 10.10.4

PS

为什么-5实际上?

理论

有两种可能的例外:

  • OutOfMemoryError: Java heap space意味着你的数组不适合Java堆空间。 为了解决您可以通过使用JVM选项-Xmx来增加最大堆大小。 还要考虑到对象的最大尺寸不能大于最大的堆代 。
  • OutOfMemoryError: Requested array size exceeds VM limit意味着OutOfMemoryError: Requested array size exceeds VM limit平台特定的大小:
    • 上限是由用于描述数组索引的大小types的限制来设置的,所以理论上的数组大小受到2^31-1=2147483647元素的限制。
    • 另一个限制是JVM /平台特定的。 根据Java语言规范第十章:Java SE 7版的数组,对数组长度没有严格的限制,因此可以在不违反JLS的情况下减小数组的大小。

实践

在HotSpot中,JVM数组的大小受内部表示的限制。 在GC代码中,JVM以堆的forms将一个数组的大小作为int传递,然后从堆字转换回jint这可能会导致溢出。 所以为了避免崩溃和意外行为,最大数组长度受(最大大小 – 头大小)的限制 。 头部大小取决于用来构build正在运行的JVM的C / C ++编译器(gcc for linux, UseCompressedClassPointers clang)以及运行时设置(如UseCompressedClassPointers )。 例如在我的linux上:

  • Java HotSpot(TM)64位服务器VM 1.6.0_45限制Integer.MAX_VALUE
  • Java HotSpot(TM)64位服务器VM 1.7.0_72限制Integer.MAX_VALUE-1
  • Java HotSpot(TM)64位服务器VM 1.8.0_40限制Integer.MAX_VALUE-2

有用的链接

只有足够的分配是不够的, 你需要有一个足够大小的堆区域 。 如你所知,堆分成几代。

对于8 GB的单个分配,您必须确保单个堆区域(加上一些开销)。 对于12 GB的-Xmx您可能仍然很短。 使用其他选项来控制旧一代的大小。

一些虚拟机在数组中保留一些标题字。

最大的“安全”数字将be 2 147 483 639 (Integer.MAX_VALUE - 8)

来源-HTTP://www.docjar.com/html/api/java/util/ArrayList.java.html

 ** 191 * The maximum size of array to allocate. 192 * Some VMs reserve some header words in an array. 193 * Attempts to allocate larger arrays may result in 194 * OutOfMemoryError: Requested array size exceeds VM limit 195 */ 196 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 

所以这取决于您的系统现在可用的最大内存

编辑:为什么它显示OOM。

元素数量= 2 147 483 639

一个元素所需的字节数= 4

总内存仅为元素8589934556 KB == 8.589934555999999 GB

现在,如果数组的总内存使用量不是8字节的倍数,那么大小会向上舍入到8的下一个重叠。

所以你需要的不仅仅是因为开销而分配的东西,而且应该是连续的记忆

那么,伊万已经正确地指出,数组的长度确实有一个明确的上限,它是依赖于JVM /平台。 实际上,更重要的是,他还指出,在代码中实际创build的数组长度将主要由您在执行时分配给程序的最大堆空间大小来控制。

我只想添加小代码片段来支持他的解释。 例如,理论上,一个数组[]应该接受长度<= INTEGER.MAX_VALUE – x(这里的x是头文件的大小,它又是JVM /平台特有的),但是假设你运行了下面的 Java程序和VM选项-Xmx32m,那么你会看到创build的数组都没有达到接近MAX_ARRAY_SIZE的长度(即2147483639)

byte []数组:1个字节
0 l = 1048576 s = 1mb
1 l = 2097152 s = 2mb
2 l = 4194304 s = 4mb
3 l = 8388608 s = 8mb
java.lang.OutOfMemoryError:Java堆空间l = 16777216 s = 16mb

char []数组:2个字节
0 l = 1048576 s = 2mb
1 l = 2097152 s = 4mb
2 l = 4194304 s = 8mb
java.lang.OutOfMemoryError:Java堆空间l = 8388608 s = 16mb

int []数组:4字节
0 l = 1048576 s = 4mb
1 l = 2097152 s = 8mb
java.lang.OutOfMemoryError:Java堆空间l = 4194304 s = 16mb

double []数组:8个字节
0 l = 1048576 s = 8mb
java.lang.OutOfMemoryError:Java堆空间l = 2097152 s = 16mb

以下是代码:

  byte[] barray = null; System.out.println("\nbyte[] array : 1 byte"); try { for (ii=0; ii < 32; ii++) { barray = new byte[(int)Math.pow(2, ii)*1024*1024]; System.out.println(ii + " l=" + barray.length + " s=" + barray.length / (1024 * 1024) + "mb"); } } catch (Throwable e) { barray = null; System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + (int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb"); } char[] carray = null; System.out.println("\nchar[] array : 2 byte"); try { for (ii=0; ii < 32; ii++) { carray = new char[(int)Math.pow(2, ii)*1024*1024]; System.out.println(ii + " l=" + carray.length + " s=" + 2*carray.length / (1024 * 1024) + "mb"); } } catch (Throwable e) { carray = null; System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + 2*(int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb"); } int[] iarray = null; System.out.println("\nint[] array : 4 byte"); try { for (ii=0; ii < 32; ii++) { iarray = new int[(int)Math.pow(2, ii)*1024*1024]; System.out.println(ii + " l=" + iarray.length + " s=" + 4*iarray.length / (1024 * 1024) + "mb"); } } catch (Throwable e) { iarray = null; System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + 4*(int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb"); } double[] darray = null; System.out.println("\ndouble[] array : 8 byte"); try { for (ii=0; ii < 32; ii++) { darray = new double[(int)Math.pow(2, ii)*1024*1024]; System.out.println(ii + " l=" + darray.length + " s=" + 8*darray.length / (1024 * 1024) + "mb"); } } catch (Throwable e) { darray = null; System.out.println(e + " l=" + (int)Math.pow(2, ii)*1024*1024 + " s=" + 8*(int)Math.pow(2, ii)*1024*1024 / (1024 * 1024) + "mb"); }