Какова стоимость хранения коробочного примитива в Java?
Насколько большой, в байтах, похож на коробочный примитив java.lang.Integer
или же java.lang.Character
на яве?
int
4 байта, типичный указатель также 4 байта (если не сжимается JVM). Таким образом, стоимость целого числа (без кеширования) 4 bytes + 4 bytes = 8 bytes
? Существуют ли еще скрытые поля внутри объекта-бокса или дополнительные накладные расходы, связанные с объектами (т. Е. Есть ли общие затраты для объектов, о которых я не знаю?).
Меня не интересуют вопросы кеширования. Я знаю, что целые числа в определенном диапазоне кэшируются JVM.
Можно перефразировать вопрос: каков максимальный коэффициент, который нужно умножить на объем памяти, используемый для упакованных значений по сравнению с примитивными значениями?
РЕДАКТИРОВАТЬ: я понимаю, что существует несколько реализаций JVM. Какова типичная стоимость в типичной 32-битной реализации HotSpot?
3 ответа
Это определяется реализацией, поэтому конкретного ответа нет. Но я должен быть в состоянии ответить на это для Hotspot.
Что вам нужно знать, так это: Hotspot всегда выравнивает объекты по 8-байтовым границам. Кроме того, есть 2 слова для каждого объекта. [1]
Если мы соберем это вместе, мы получим:
32-разрядная виртуальная машина: 4-байтовое целое число + 2 слова, заголовок объекта = 12 байт. Это не кратно 8, поэтому в результате стоимость 1 целого числа будет следующим кратным 8: 16 байт.
64-битная виртуальная машина: 4-байтовое целое число + 2 слова = 20 байт. Снова округление: размер 24 байта.
Размер ссылки, очевидно, не влияет на размер самого объекта, за исключением случаев, когда он имеет ссылки на другие объекты, чего нельзя сказать о простой оболочке типа int. Если бы это было так, у нас было бы 4 байта на ссылку для 32-битных и 4 байта для куч <= 32 ГБ с CompressedOops
на современных JVM (иначе 8-байтовых) для 64-битных JVM.
[1] Заинтересованные люди могут посмотреть код в share/vm/oops/oop.hpp
Одним очень маленьким дополнением к этим ответам является то, что для упакованных примитивов происходит некоторая дедупликация. Например,Integer::valueOf(int)
использует java.lang.IntegerCache
который использует экземпляры Integer со значениями в диапазоне -128..127
. Итак, у вас есть упомянутые выше размеры для объектов в штучной упаковке, но не каждый из них может быть отдельным объектом.
Это больше, чем это.
Каждая ссылка на объект имеет дополнительные издержки, такие как ссылка на класс. Мало того, ваш 4-байтовый указатель не совсем точен. Это ссылка, так что это идентификатор плюс указатель, И этот указатель может быть 8 байтов, если вы используете 64-битную JVM.
По-видимому, также существуют различия в реализации виртуальных машин. Лучший способ быть уверенным в этом - использовать его в профилировщике.
Моя оценка (Super SWAG) будет. Ссылка на объект 16 байтов (64-битная JVM) Ссылка на класс 16-байтовое примитивное значение 4 байта (при условии int.) Всего. 36 байтов.
РЕДАКТИРОВАТЬ: Теперь, когда вы укажите 32-битную JVM, моя SWAG будет 20 байтов, используя ту же математику выше.
Я знаю, что это не совсем отвечает на ваш вопрос о стоимости хранения примитивов в штучной упаковке, но я чувствую из вашего вопроса, что вы сомневаетесь, оправдано ли их использование.
Вот отрывок из книги "Эффективное Java (2-е издание)" Джошуа Блоха, который должен помочь вам принять решение:
"So when should you use boxed primitives? They have several legitimate uses. The
first is as elements, keys, and values in collections. You can’t put primitives in collections, so you’re forced to use boxed primitives. This is a special case of a more general one. You must use boxed primitives as type parameters in parame- terized types (Chapter 5), because the language does not permit you to use primi- tives. For example, you cannot declare a variable to be of type Thread- Local<int>, so you must use ThreadLocal<Integer> instead. Finally, you must use boxed primitives when making reflective method invocations (Item 53).
In summary, use primitives in preference to boxed primitives whenever you have the choice. Primitive types are simpler and faster. If you must use boxed primitives, be careful! Autoboxing reduces the verbosity, but not the danger, of using boxed primitives. When your program compares two boxed primitives with the == operator, it does an identity comparison, which is almost certainly not what you want. When your program does mixed-type computations involving boxed and unboxed primitives, it does unboxing, and when your program does unboxing, it can throw a NullPointerException. Finally, when your program boxes primitive values, it can result in costly and unnecessary object creations."
Надеюсь, это поможет.