Почему я не могу создать массив с большим размером?

почему невозможно создать массив с максимальным размером int?

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

Я нашел такое объяснение:

массивы Java доступны через 32-разрядные ints, в результате чего максимальный теоретический размер массива составляет 2147483647 элементов.

но как вы можете видеть, мой код не работает. Также невозможно создать массив с размером

new int[Integer.MAX_VALUE - 5];

технические детали

  • 64-разрядная точка доступа JVM
  • на OSX 10.10.4

PS

и почему -5 на самом деле?

5 ответов


теория

возможны два исключения:

  • OutOfMemoryError: Java heap space означает, что Ваш массив не вписывается в пространство кучи java. Для решения вы можете увеличить максимальный размер кучи, используя опцию JVM -Xmx. Также примите во внимание, что максимальный размер объекта не может быть больше самого большого поколения кучи.
  • OutOfMemoryError: Requested array size exceeds VM limit превышен размер, специфичный для платформы:
    • верхний предел устанавливается ограничения типа размера, используемого для описания индекса в массиве, поэтому теоретический размер массива ограничен 2^31-1=2147483647 элементы.
    • другой предел специфичен для JVM / платформы. Согласно Глава 10: массивы спецификации языка Java, Java SE 7 Edition нет строгого ограничения на длину массива, поэтому размер массива может быть уменьшен без нарушения JLS.

практика

в HotSpot JVM размер массива ограничено внутренним представительством. В коде GC JVM передает размер массива в словах кучи как int затем преобразует обратно из кучи слов в jint это может вызвать переполнение. Поэтому во избежание сбоев и неожиданного поведения максимальная длина массива ограничена (максимальный размер - размер заголовка). Где заголовок зависит от компилятора C/C++, который использовался для создания JVM, который вы используете(gcc для linux, clang для macos), и параметров среды выполнения(например UseCompressedClassPointers). Например, на моем linux:

  • Java HotSpot (TM) 64-разрядный сервер VM 1.6.0_45 limit 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 ГБ вы должны обеспечить это для одной области кучи (плюс некоторые накладные расходы). С 12 ГБ -Xmx вы все еще можете быть короткими. Используйте дополнительные опции для управления размером старого поколения.


некоторые VMs резервируют некоторые слова заголовка в массиве.

максимальное "безопасное" число be 2 147 483 639 (Integer.MAX_VALUE - 8)

Source-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;

поэтому это зависит от максимальной памяти, доступной вашему JVM в вашей системе сейчас

Edit: почему он показывает OOM.

количество элементов = 2 147 483 639

количество байтов, необходимых для одного элемента = 4

общая память только для элемента 8589934556 КБ == 8.589934555999999 ГБ

теперь, если общее использование памяти массива не кратно 8 байтам, то размер округляется до следующего mutlitple 8 .

таким образом, вам нужно больше, чем то, что вы выделяете из-за накладных расходов, и это должна быть непрерывная память


Ну, Иван уже правильно указал, что длина массива имеет хорошо определенный верхний предел и что он снова зависит от JVM/платформы. На самом деле, что более важно, он также заявил, что сколько длины массива вы можете фактически создать в своем коде, в основном будет контролироваться тем, сколько максимального пространства кучи вы выделили своей программе во время выполнения.

Я просто хотел бы добавить небольшой фрагмент кода, чтобы поддержать его объяснение. Например, теоретически, массив [] должен принимать length после Java-программа с опцией VM -Xmx32m тогда вы увидите, что ни один из созданных массивов не достигает длины, близкой к MAX_ARRAY_SIZE (т. е. 2147483639)

Byte[] массив : 1 байт
0 l=1048576 s=1 Мб
1 л=2097152 с=2 Мб
2 l=4194304 s=4 МБ
3 l=8388608 s=8 МБ
Ява.ленг.OutOfMemoryError: пространство кучи Java l=16777216 s=16mb

char[] массив: 2 байта
0 l=1048576 s=2 Мб
1 л=2097152 с=4 МБ
2 l=4194304 s=8 МБ
Ява.ленг.OutOfMemoryError: пространство кучи Java l=8388608 s=16mb

int[] массив: 4 байта
0 l=1048576 s=4 МБ
1 л=2097152 с=8 МБ
Ява.ленг.OutOfMemoryError: пространство кучи Java l=4194304 s=16 МБ

двойной[] массив : 8 байт
0 l=1048576 s=8 МБ
Ява.ленг.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");
    }

найдите максимальный размер кучи, перейдя в cmd и введите эту строку

javaw -XX:+PrintFlagsFinal | find "MaxHeapSize"

а затем разделить его на 1.5, вы получите приблизительный максимальный размер массива для вашего компьютера