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

Другие вопросы по тегам