Почему я не могу создать массив большого размера?
Почему невозможно создать массив с максимальным размером 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
, вы получите приблизительный максимальный размер массива для вашего компьютера.