Как целочисленные массивы хранятся внутри, в JVM? - PullRequest
5 голосов
/ 17 сентября 2008

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

int[] vs. Integer[]

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

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

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

Ответы [ 5 ]

11 голосов
/ 17 сентября 2008

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

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

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

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

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

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

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

3 голосов
/ 17 сентября 2008

Джон Роуз работает над fixnums в JVM, чтобы решить эту проблему.

1 голос
/ 17 сентября 2008

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

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

0 голосов
/ 17 сентября 2008

Причина, по которой 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 правильным решением.

0 голосов
/ 17 сентября 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...