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

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

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

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

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

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

new int[Integer.MAX_VALUE - 5];

Технические данные

  • 64-бит HotSpot JVM
  • OSX 10.10.4

PS

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

Ответ 1

теория

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

  • 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.

практика

Размер массива JSM HotSpot ограничен внутренним представлением. В коде 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 limit Integer.MAX_VALUE-1
  • Java HotSpot (TM) 64-разрядный сервер VM 1.8.0_40 limit Integer.MAX_VALUE-2

Полезные ссылки

Ответ 2

Некоторые виртуальные машины резервируют некоторые заголовочные слова в массиве.

Максимальное "безопасное" число будет 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;

Так что это зависит от максимальной памяти, доступной вашей JVM, на вашей системе "СЕЙЧАС"

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

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

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

Общая память только для элемента 8589934556 KB == 8.589934555999999 RU

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

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

Ответ 3

Этого недостаточно, чтобы иметь достаточно кучи для этого распределения; вам нужно иметь одну область кучи достаточного размера. Как вы знаете, куча разделена на поколения.

Для одного распределения в 8 ГБ вы должны обеспечить, чтобы многое для одной области кучи (плюс некоторые накладные расходы). С 12 ГБ -Xmx вы все равно можете быть короткими. Используйте дополнительные параметры для управления размером старого поколения.

Ответ 4

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

Я просто хотел бы добавить небольшой фрагмент кода, чтобы поддержать его объяснение. Например, теоретически массив [] должен принимать длину & ​​lt; = INTEGER.MAX_VALUE - x (здесь x - размер заголовка, который снова является JVM/платформой), но предположим, что вы запускаете следующую программу Java с VM option -Xmx32m, то вы увидите, что ни один из созданного массива не достигнет длины, близкой к 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 [] array: 4 байт
0 l = 1048576 s = 4mb
1 l = 2097152 s = 8mb
java.lang.OutOfMemoryError: пространство кучи Java l = 4194304 s = 16mb

double [] array: 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");
    }

Ответ 5

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

javaw -XX:+PrintFlagsFinal | find "MaxHeapSize"

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