Почему невозможно создать массив размера MAX_INT в Java?
Я прочитал некоторые ответы на этот вопрос ( Почему я не могу создать массив большого размера? И https://bugs.openjdk.java.net/browse/JDK-8029587), и я не понимаю следующее. "В коде GC мы передаем размер объектов в словах как int". Как я знаю размер слова в JVM составляет 4 байта. В соответствии с этим, если мы передаем размер длинного массива большого размера (например, MAX_INT - 5) в словах как int, мы должны получить исключение OutOfMemoryException с размером запрашиваемого массива, превышающим лимит VM, поскольку размер слишком велик для int даже без размера заголовка. Так почему же массивы разных типов имеют одинаковое ограничение на максимальное количество элементов?
2 ответа
Только в отношении того, почему массивы разных типов имеют одинаковое ограничение на максимальное количество элементов? часть:
Потому что это не имеет большого значения в практической реальности; но позволяет коду, реализующему JVM, быть проще.
Когда есть только один предел; это одинаково для всех видов массивов; тогда вы можете обработать все массивы с этим кодом. Вместо того, чтобы иметь много специфичного для типа кода.
И учитывая тот факт, что люди, которым нужны "большие" массивы, все еще могут их создавать; и затрагиваются только те, кому нужны действительно большие массивы; зачем тратить эти усилия?
Насколько я могу судить, ответ в источниках jdk (я смотрю на jdk-9); также после написания я не уверен, должен ли это быть комментарий (и если он отвечает на ваш вопрос), но это слишком долго для комментария...
Сначала выдается ошибка из hotspot/src/share/vm/oops/arrayKlass.cpp
Вот:
if (length > arrayOopDesc::max_array_length(T_ARRAY)) {
report_java_out_of_memory("Requested array size exceeds VM limit");
....
}
Сейчас, T_ARRAY
на самом деле перечисление типа BasicType
это выглядит так:
public static final BasicType T_ARRAY = new BasicType(tArray);
// tArray is an int with value = 13
Это первый признак того, что при вычислении максимального размера jdk не заботится о том, что будет содержать этот массив (T_ARRAY
не указывает, какие типы будут содержать этот массив).
Теперь метод, который фактически проверяет максимальный размер массива, выглядит следующим образом:
static int32_t max_array_length(BasicType type) {
assert(type >= 0 && type < T_CONFLICT, "wrong type");
assert(type2aelembytes(type) != 0, "wrong type");
const size_t max_element_words_per_size_t =
align_size_down((SIZE_MAX/HeapWordSize - header_size(type)), MinObjAlignment);
const size_t max_elements_per_size_t =
HeapWordSize * max_element_words_per_size_t / type2aelembytes(type);
if ((size_t)max_jint < max_elements_per_size_t) {
// It should be ok to return max_jint here, but parts of the code
// (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for
// passing around the size (in words) of an object. So, we need to avoid
// overflowing an int when we add the header. See CRs 4718400 and 7110613.
return align_size_down(max_jint - header_size(type), MinObjAlignment);
}
return (int32_t)max_elements_per_size_t;
}
Я не слишком погружался в код, но он основан на HeapWordSize
; который 8 bytes at least
, Вот хорошая ссылка (я пытался найти его в самом коде, но ссылок на него слишком много).