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