Как целочисленные массивы хранятся внутри, в JVM?

StackOverflow https://stackoverflow.com/questions/76549

  •  09-06-2019
  •  | 
  •  

Вопрос

Массив целых чисел в java хранится в памяти в виде блока 32-битных значений.Как хранится массив целочисленных объектов?т. е.

int[] vs. Integer[]

Я бы предположил, что каждый элемент в целочисленном массиве является ссылкой на целочисленный объект, и что Целочисленный объект имеет накладные расходы на хранение объекта, как и любой другой объект.

Однако я надеюсь, что JVM выполняет какую-то магическую хитрость под капотом, учитывая, что целые числа неизменяемы, и сохраняет их точно так же, как массив целых чисел.

Неужели моя надежда прискорбно наивна?Является ли целочисленный массив намного медленнее, чем массив int в приложении, где важна каждая унция производительности?

Это было полезно?

Решение

Ни одна известная мне виртуальная машина не будет хранить массив Integer[] подобно массиву int[] по следующим причинам:

  1. Там может быть ноль Целочисленные объекты в массиве, и у вас не осталось битов для указания этого в массиве int.Однако виртуальная машина могла бы хранить эту 1-битную информацию для каждого слота массива в скрытом битовом массиве.
  2. Вы можете синхронизировать элементы целочисленного массива.Это гораздо сложнее преодолеть в качестве первого пункта, поскольку вам пришлось бы хранить объект monitor для каждого слота массива.
  3. Элементы Integer[] могут быть сравнены на предмет идентичности.Вы могли бы, например, создать два целочисленных объекта со значением 1 через новое и храните их в разных слотах массива, а позже вы извлекаете их и сравниваете с помощью == .Это должно привести к значению false, поэтому вам придется где-то хранить эту информацию.Или вы сохраняете ссылку на один из объектов Integer где-нибудь и используете это для сравнения, и вы должны убедиться, что одно из сравнений == равно false, а одно true.Это означает, что вся концепция идентификации объекта очень сложна в обращении для оптимизированный Целочисленный массив.
  4. Вы можете привести целое число [], например, кObject[] и передайте его методам, ожидающим только Object[].Это означает, что весь код, который обрабатывает Object[], теперь должен уметь обрабатывать и специальный объект Integer[], что делает его медленнее и больше.

Принимая все это во внимание, вероятно, можно было бы создать специальное целое число [], которое экономит некоторое пространство по сравнению с наивный реализация, но дополнительная сложность, вероятно, повлияет на множество других кодов, что в конечном итоге сделает его медленнее.

Накладные расходы, связанные с использованием Integer[] вместо int[], могут быть очень большими в пространстве и времени.На типичной 32-разрядной виртуальной машине целочисленный объект будет занимать 16 байт (8 байт для заголовка объекта, 4 для полезной нагрузки и 4 дополнительных байта для выравнивания), в то время как Integer[] использует столько же места, сколько int[].В 64-разрядных виртуальных машинах (использующих 64-разрядные указатели, что не всегда так) целочисленный объект будет занимать 24 байта (16 для заголовка, 4 для полезной нагрузки и 4 для выравнивания).Кроме того, слот в Integer[] будет использовать 8 байт вместо 4, как в int[].Это означает, что вы можете ожидать накладных расходов в размере с 16 по 28 байт на слот, который является коэффициент от 4 до 7 по сравнению с обычными массивами int.

Накладные расходы на производительность также могут быть значительными главным образом по двум причинам:

  1. Поскольку вы используете больше памяти, вы оказываете гораздо большее давление на подсистему памяти, повышая вероятность промахов в кэше в случае Integer[].Например, если вы просматриваете содержимое int[] линейным способом, в кэше будет большинство записей, уже извлеченных, когда они вам понадобятся (поскольку макет тоже линейный).Но в случае целочисленного массива сами целочисленные объекты могут быть случайным образом разбросаны в куче, что затрудняет кешированию угадать, на что будет указывать следующая ссылка на память.
  2. Сборке мусора приходится выполнять гораздо больше работы из-за используемой дополнительной памяти и потому, что она должна сканировать и перемещать каждый целочисленный объект отдельно, в то время как в случае int[] это всего лишь один объект, и содержимое объекта не нужно сканировать (они не содержат ссылок на другие объекты).

Подводя итог, можно сказать, что использование int[] в работе, критичной к производительности, будет намного быстрее и эффективнее с использованием памяти, чем использование массива целых чисел в текущих виртуальных машинах, и маловероятно, что это сильно изменится в ближайшем будущем.

Другие советы

Джон Роуз работает над фиксированные суммы в JVM нужно исправить эту проблему.

Я думаю, что ваша надежда прискорбно наивна.В частности, необходимо решить проблему, заключающуюся в том, что Integer потенциально может быть null, тогда как int не может быть.Одного этого достаточно для сохранения указателя на объект.

Тем не менее, фактический указатель объекта будет относиться к неизменяемому экземпляру int, особенно для выбранного подмножества целых чисел.

Это будет ненамного медленнее, но поскольку Integer[] должен принимать "null" в качестве записи, а int[] этого делать не обязательно, потребуется некоторое количество бухгалтерии, даже если Integer[] поддерживается int[] .

Итак, если важна каждая унция производительности, user int[]

Причина, по которой Integer может быть null, тогда как int не может, заключается в том, что Integer - это полноценный Java-объект со всеми накладными расходами, которые он включает.В этом есть ценность, поскольку вы можете писать

Integer foo = new Integer();
foo = null; 

это хорошо для того, чтобы сказать, что foo будет иметь значение, но пока этого нет.

Еще одно отличие заключается в том, что int не выполняет вычисления переполнения.Например,

int bar = Integer.MAX_VALUE;
bar++;

будет весело увеличивать полосу, и в итоге вы получите очень отрицательное число, которое, вероятно, не является тем, что вы предполагали в первую очередь.

foo = Integer.MAX_VALUE;
foo++;

буду жаловаться, что, я думаю, было бы лучшим поведением.

И последний момент заключается в том, что Integer, будучи объектом Java, несет с собой накладные расходы на пространство объекта.Я думаю, что кому-то еще может понадобиться вмешаться здесь, но я считаю, что каждый объект потребляет 12 байт на служебные данные, а затем пространство для самого хранилища данных.Если вам нужны производительность и пространство, я задаюсь вопросом, является ли Integer правильным решением.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top