Максимальный размер Java-массивов?

214

Есть ли ограничение на количество элементов, которые может содержать массив Java? Если так, то, что это?

ящерица
источник
5
Вы приняли неправильный ответ, просто попробуйте выделить такой длинный массив (и нет, мне не хватает памяти).
Maaartinus
Близко связаны: stackoverflow.com/questions/878309/…
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
Правильный ответ - stackoverflow.com/questions/31382531/…
Иван Мамонтов

Ответы:

184

Не нашел правильного ответа, хотя это очень легко проверить.

В недавнем HotSpot VM, правильный ответ Integer.MAX_VALUE - 5. Как только вы выйдете за пределы этого:

public class Foo {
  public static void main(String[] args) {
    Object[] array = new Object[Integer.MAX_VALUE - 4];
  }
}

Ты получаешь:

Exception in thread "main" java.lang.OutOfMemoryError:
  Requested array size exceeds VM limit
Кевин Бурриллион
источник
57
Я думаю, что идея понижения голосов не имеет смысла, если мы не хотим понизить ответы, которые являются простыми и просто неправильными . Имеет ли значение разница в пять байтов в реальном мире, НЕТ, конечно, нет. Но меня беспокоит, что люди готовы дать ответ «авторитетно», даже не пытаясь увидеть, действительно ли это работает. Что касается лимита памяти, ну да. Это как если бы вы спросили меня "сколько винограда вы можете съесть?" и я сказал: «Ну, это зависит от того, сколько у меня в холодильнике в то время».
Кевин Бурриллион
7
Вы случайно не знаете, почему он не даст вам эти пять байтов? Обязательно ли это то, что всегда происходит в Java, или это может быть связано с памятью вашего компьютера или с чем-то еще?
Таймон
17
@Kevin Bourrillion: похоже, что это изменилось, используя Oracle 1.7.0_07, который я могу выделить до MAX_VALUE-2элементов. Это не зависит от того, что я выделяю, и мне действительно интересно, для чего виртуальная машина может использовать две «вещи» (длина не помещается в 2 байта).
Maaartinus
3
@ TomášZato, последняя версия, у Integer.MAX_VALUE+1вас будет целочисленное переполнение. Размеры массива в Java есть int, нет long; независимо от того, какой тип данных вы храните в своем массиве, байтах или ссылках. Строки - это просто ссылки на объекты.
ВЫЙТИ - Anony-Mousse
8
Максимальное количество элементов в массиве в JDK 6 и выше Integer.MAX_VALUE - 2= 2 147 483 645. Java успешно выделяет такой массив, если вы запускаете его с -Xmx13G. Это не с, OutOfMemoryError: Java heap spaceесли вы пройдете -Xmx12G.
Алексей Иванов
127

Это (конечно) полностью VM-зависимый.

Просматривая исходный код OpenJDK 7 и 8 java.util.ArrayList, .Hashtable, .AbstractCollection, .PriorityQueue, и .Vectorвы можете увидеть это утверждение повторяется:

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

который добавлен Мартином Бухгольцем (Google) 2010-05-09 ; проверено Крисом Хегарти (Oracle).

Таким образом, вероятно, мы можем сказать, что максимальное «безопасное» число будет 2 147 483 639 ( Integer.MAX_VALUE - 8), а «попытки выделить большие массивы могут привести к OutOfMemoryError ».

(Да, отдельная претензия Бухгольца не включает подтверждающих доказательств, так что это расчетное обращение к авторитету. Даже в самом OpenJDK мы можем видеть подобный код, return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;который показывает, что MAX_ARRAY_SIZEон еще не имеет реального использования.)

Pacerier
источник
И почему мы должны добавить -8?
JohnWinter
@Pacerier. Разве это MAX_ARRAY_SIZE не должно применяться, только когда вы используете ArrayList? Это отличается от использования массива типа int [] array = new int [some_value_here]; не так ли? Почему константа, определенная в ArrayList, может быть применена к обычному массиву (определенному с помощью [])? Они одинаковы за кулисами?
Тиаго
1
@Tiago, нет, сам код не имеет никакого отношения к максимальному размеру массивов. Это просто претензия.
Pacerier
@JohnWinter, цитата гласит: «Некоторые виртуальные машины резервируют некоторые заголовочные слова в массиве». Таким образом, -8из-за байтов зарезервированные слова заголовка будут занимать.
Pacerier
38

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

tvanfosson
источник
27

Продолжая эту статью http://en.wikipedia.org/wiki/Criticism_of_Java#Large_arrays :

Java подверглась критике за то, что она не поддерживала массивы более чем 2 31 -1 (около 2,1 миллиарда) элементов. Это ограничение языка; Спецификация языка Java, раздел 10.4, гласит, что:

Массивы должны быть проиндексированы значениями int ... Попытка доступа к компоненту массива с длинным значением индекса приводит к ошибке времени компиляции.

Поддержка больших массивов также потребует изменений в JVM. Это ограничение проявляется в таких областях, как количество коллекций, ограниченное 2 миллиардами элементов, и невозможность хранения файлов карты размером более 2 ГиБ. В Java также отсутствуют настоящие многомерные массивы (непрерывно выделяемые отдельные блоки памяти, доступ к которым осуществляется по одной косвенной ссылке), что ограничивает производительность для научных и технических вычислений.

работает
источник
6
В Java нет синтаксического сахара для многомерных массивов, но вы все равно можете «иметь» их с небольшим умножением (если только общий размер массива не превысил вышеупомянутый предел)
kbolino
11

Массивы индексируются неотрицательным целым числом, поэтому максимальный размер массива, к которому вы можете получить доступ, будет Integer.MAX_VALUE. Другое дело, насколько большой массив вы можете создать. Это зависит от максимального объема доступной памяти JVMи типа содержимого массива. Каждый элемент массива имеет свой размер, пример. byte = 1 byte, int = 4 bytes,Object reference = 4 bytes (on a 32 bit system)

Так что, если у вас есть 1 MBдоступная память на вашем компьютере, вы можете выделить массив byte[1024 * 1024]или Object[256 * 1024].

Отвечая на ваш вопрос - Вы можете выделить размер массива (максимально доступная память / размер элемента массива).

Резюме - теоретически максимальный размер массива будет Integer.MAX_VALUE. Практически это зависит от того, сколько памяти у вас JVMесть и сколько уже выделено другим объектам.

Dhanuka
источник
3

Я пытался создать байтовый массив, как это

byte[] bytes = new byte[Integer.MAX_VALUE-x];
System.out.println(bytes.length);

С этой конфигурацией запуска:

-Xms4G -Xmx4G

И Java-версия:

Версия Openjdk "1.8.0_141"

Среда выполнения OpenJDK (сборка 1.8.0_141-b16)

64-битная серверная виртуальная машина OpenJDK (сборка 25.141-b16, смешанный режим)

Это работает только для x> = 2, что означает, что максимальный размер массива равен Integer.MAX_VALUE-2

Значения выше этого дают

Исключение в потоке "main" java.lang.OutOfMemoryError: Размер запрашиваемого массива превышает ограничение виртуальной машины в Main.main (Main.java:6)

Василис Николау
источник
2

Да, есть ограничение на массив Java. Java использует целое число в качестве индекса массива, а максимальное целочисленное хранилище JVM составляет 2 ^ 32. так что вы можете хранить 2 147 483 647 элементов в массиве.

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

Авинаш Барде
источник
1

Максимальное количество элементов arrayis (2^31)−1или2 147 483 647

малыш
источник
5
Java не может выделить массив размера Integer.MAX_VALUE - 1, вы получите «java.lang.OutOfMemoryError: Запрошенный размер массива превышает ограничение виртуальной машины». Максимальное количество элементов в JDK 6 и выше Integer.MAX_VALUE - 2= 2 147 483 645.
Алексей Иванов
0

На самом деле это ограничение Java, ограничивающее 2 ^ 30-4 1073741820. Не 2 ^ 31-1. Не знаю почему, но я проверил это вручную на JDK.2 ^ 30-3 до сих пор бросает вм, кроме

Редактировать: исправлено от -1 до -4, проверено на windows jvm

Ferned
источник
Вы используете 32-битную JVM. Используйте 64-битную JVM, и предел JVM будет близок к 2 ^ 31. (Вам также необходимо доступное пространство кучи, которое не является значением по умолчанию и будет зависеть от вашей физической памяти.)
dave_thompson_085