Integer vs int: with regard to memory
@craig: Because as you hinted at in your answer, it’s totally up to the JVM implementation how much heap space it wants to take for each of those things. If I’m not mistaken, there’s nothing that would stop a compliant JVM from storing an int as 128 bits, as long as that decision doesn’t leak out to the hosted program. All you can know is that the «width» of int and Integer are the same; they can both represent the same number of values.
4 Answers 4
In general, the heap memory used by a Java object in Hotspot consists of:
- an object header, consisting of a few bytes of «housekeeping» information;
- memory for primitive fields, according to their size (int n->32 bits)
- memory for reference fields (4 bytes each) (Integer n ->32 bits)
- padding: potentially a few «wasted» unused bytes after the object data, to make every object start at an address that is a convenient multiple of bytes and reduce the number of bits required to represent a pointer to an object.
as per the suggestion of Mark Peters I would like add the link below http://www.javamex.com/tutorials/memory/object_memory_usage.shtml
Upvote for being the only answer to qualify it with «in Hotspot». But downvote for not citing your source.
Also note that in addition to the heap memory requirement for the object (which may well be «zero» if a cached instance is re-used many times, as happens with Integer.valueOf(small) ), you still need to store the pointer to the object in your stack frame or containing object. That is another 32 or 64 bits, i.e. the pointer also is already at least as big as an int .
An Integer object in Java occupies 16 bytes.
I don’t know whether running a 64- vs 32-bit JVM makes a difference. For primitive types, it does not matter. But I can not say for certain how the memory footprint of an object changes (if at all) under a 64-bit system.
You can test this for yourself here:
int is a primitive data type which takes 32 bits(4 bytes) to store.
When your Java code uses the new operator to create an instance of a Java object, much more data is allocated than you might expect. For example, it might surprise you to know that the size ratio of an int value to an Integer object — the smallest object that can hold an int value — is typically 1:4.
Integer is an object which takes 128 bits (16 bytes) to store int value.
When we creates new Integer using new Operator it allocates memory as per follows.
- Class Object(32 bits) — which consist of a pointer to the class information, which describes the object in our case its point to java.lang.Integer class
- Flags (32 bits)- It is collection of flags that describes the state of object. Like is it has hash-code, is it array or not i.e. its Shape.
- Lock (32 bits) — It stores synchronization information of object. whether the object currently synchronized or not.
Above 3 points are called as metadata of an Object.
- Lastly metadata is followed by the Object data (32 bits) itself. In case of Integer its single int value.
All the above explanation is as per 32 bit processor architecture. It can differ from JVM version and vendor.
Размер Java объектов
Знаете сколько в памяти занимает строка? Каких только я не слышал ответов на этот вопрос, начиная от «не знаю» до «2 байта * количество символов в строке». А сколько тогда занимает пустая строка? А знаете сколько занимает объект класса Integer? А сколько будет занимать Ваш собственный объект класса с тремя Integer полями? Забавно, но ни один мой знакомый Java программист не смог ответить на эти вопросы… Да, большинству из нас это вообще не нужно и никто в реальных java проектах не будет об этом думать. Но это, ведь, как не знать объем двигателя машины на которой Вы ездите. Вы можете быть прекрасным водителем и даже не подозревать о том, что значат цифры 2.4 или 1.6 на вашей машине. Но я уверен, что найдется мало людей, которые не знакомы со значением этих цифр. Так почему же java программисты так мало знают об этой части своего инструмента?
Integer vs int
Все мы знаем, что в java — everything is an object. Кроме, пожалуй, примитивов и ссылок на сами объекты. Давайте рассмотрим две типичных ситуации:
//первый случай int a = 300; //второй случай Integer b = 301;
В этих простых строках разница просто огромна, как для JVM так и для ООП. В первом случае, все что у нас есть — это 4-х байтная переменная, которая содержит значение из стека. Во втором случае у нас есть ссылочная переменная и сам объект, на который эта переменная ссылается. Следовательно, если в первом случае мы определено знаем, что занимаемый размер равен:
sizeOf(reference) + sizeOf(Integer)
Забегая вперед скажу — во втором случае количество потребляемой памяти приблизительно в 5 раз больше и зависит от JVM. А теперь давайте разберемся, почему разница настолько огромна.
Из чего же состоит объект?
- Заголовок объекта;
- Память для примитивных типов;
- Память для ссылочных типов;
- Смещение/выравнивание — по сути, это несколько неиспользуемых байт, что размещаются после данных самого объекта. Это сделано для того, чтобы адрес в памяти всегда был кратным машинному слову, для ускорения чтения из памяти + уменьшения количества бит для указателя на объект + предположительно для уменьшения фрагментации памяти. Стоит также отметить, что в java размер любого объекта кратен 8 байтам!
Структура заголовка объекта
- Маркировочное слово (mark word) — к сожалению мне так и не удалось найти назначение этой информации, подозреваю что это просто зарезервированная на будущее часть заголовка.
- Hash Code — каждый объект имеет хеш код. По умолчанию результат вызова метода Object.hashCode() вернет адрес объекта в памяти, тем не менее некоторые сборщики мусора могут перемещать объекты в памяти, но хеш код всегда остается одним и тем же, так как место в заголовке объекта как раз может быть использовано для хранения оригинального значения хеш кода.
- Garbage Collection Information — каждый java объект содержит информацию нужную для системы управления памятью. Зачастую это один или два бита-флага, но также это может быть, например, некая комбинация битов для хранения количества ссылок на объект.
- Type Information Block Pointer — содержит информацию о типе объекта. Этот блок включает информацию о таблице виртуальных методов, указатель на объект, который представляет тип и указатели на некоторые дополнительные структуры, для более эффективных вызовов интерфейсов и динамической проверки типов.
- Lock — каждый объект содержит информацию о состоянии блокировки. Это может быть указатель на объект блокировки или прямое представление блокировки.
- Array Length — если объект — массив, то заголовок расширяется 4 байтами для хранения длины массива.
Спецификация Java
Известно, что примитивные типы в Java имеют предопределенный размер, этого требует спецификация для переносимости кода. Поэтому не будем останавливаться на примитивах, так как все прекрасно описано по ссылке выше. А что же говорит спецификация для объектов? Ничего, кроме того, что у каждого объекта есть заголовок. Иными словами, размеры экземпляров Ваших классов могут отличатся от одной JVM к другой. Собственно, для простоты изложения я буду приводить примеры на 32-х разрядной Oracle HotSpot JVM. А теперь давайте разберем самые используемые классы Integer и String.
Integer и String
Итак, давайте попробуем подсчитать сколько же будет занимать объект класса Integer в нашей 32-х разрядной HotSpot JVM. Для этого нужно будет заглянуть в сам класс, нам интересны все поля, которые не объявлены как static. Из таких видим только одно — int value. Теперь исходя из информации выше получаем:
Заголовок: 8 байт Поле int: 4 байта Выравнивание для кратности 8 : 4 байта Итого: 16 байт
private final char value[]; private final int offset; private final int count; private int hash;
Заголовок: 8 байт Поля int: 4 байта * 3 == 12 байт Ссылочная переменная на объект массива: 4 байта Итого: 24 байта
Ну и это еще не все… Так как строка содержит ссылку на массив символов, то, по сути, мы имеем дело с двумя разными объектами — объектом класса String и самим массивом, который хранит строку. Это, как бы, верно с точки зрения ООП, но если посмотреть на это со стороны памяти, то к полученному размеру нужно добавить и размер выделенного для символов массива. А это еще 12 байт на сам объект массива + 2 байта на каждый символ строки. Ну и, конечно же, не забываем добавлять выравнивание для кратности 8 байтам. Итого в конечном итоге простая, казалось бы, строка new String(«a») выливается в:
new String() Заголовок: 8 байт Поля int: 4 байта * 3 == 12 байт Ссылочная переменная на объект массива: 4 байта Итого: 24 байта new char[1] Заголовок: 8 байт + 4 байта на длину массива == 12 байт Примитивы char: 2 байта * 1 == 2 байта Выравнивание для кратности 8 : 2 байта Итого: 16 байта Итого, new String("a") == 40 байт
Важно отметить, что new String(«a») и new String(«aa») будут занимать одинаковое количество памяти. Это важно понимать. Типичный пример использования этого факта в свою пользу — поле hash в классе String. Если бы его не было, то объект строки так или иначе занимал бы 24 байта, за счет выравнивания. А так получается что для этих 4-х байтов нашлось очень достойное применение. Гениальное решение, не правда ли?
Размер ссылки
Немножко хотел бы оговорится о ссылочных переменных. В принципе, размер ссылки в JVM зависит от ее разрядности, подозреваю, что для оптимизации. Поэтому в 32-х разрядных JVM размер ссылки обычно 4 байта, а в 64-х разрядных — 8 байт. Хотя это условие и не обязательно.
Группировка полей
- 1. 8-ми байтовые типы(double и long)
- 2. 4-х байтовые типы(int и float)
- 3. 2-х байтовые типы(short и char)
- 4. Одно байтовые типы(
booleanи byte) - 5. Ссылочные переменные
Зачем все это?
Иногда возникает ситуация в которой Вам необходимо прикинуть приблизительный объем памяти для хранения тех или иных объектов, например словаря, эта маленькая справка поможет быстро сориентироваться. Также, это потенциально возможный способ оптимизации, особенно в том окружении, где доступ к его настройкам не доступен.
Выводы
Тема памяти в java очень интересна и обширна, когда я начинал писать эту статью, то думал что уложусь в пару примеров с выводами. Но чем дальше и глубже копаешь, тем больше и интересней становится. Вообще, знать как выделяется память для объектов очень полезная вещь, так как поможет Вам сэкономить память, предотвратить подобные проблемы или оптимизировать вашу программу в местах, где это казалось невозможным. Конечно, места где можно использовать такие оптимизации — очень редки, но все же… Надеюсь статья была Вам интересной.
Так сколько занимает реально в оперативной памяти int и long в Java?
Ясное дело что int и long — 32 и 64 бита соответственно. Но где-то я слышал что и byte и short и int и long занимают в памяти одинаковое количество памяти, а разница в них ограничением значения. Правда ли это? Гугл не помог.
Оценить 3 комментария
Говорят что byte, short и long принимает на выходе тип int
Самому интересно это, вот я когда то задавал вопрос где я это и услышал: ссылка
На стеке ничто не занимает меньше 4 байт, потому что в байт-коде есть только инструкции для операций с int, long, float, double и объектными ссылками на стеке: https://en.wikipedia.org/wiki/Java_bytecode_instru.
В памяти объектов все типы занимают «нужное» кол-во байт (за исключением boolean, который мог бы занимать всего один бит, а занимает целый байт, см. java.util.BitSet), но из-за выравнивания объектов (размеры объектов выравниваются по-умолчанию (и как минимум) на границу 8 байт в Hotspot JVM) зачастую получается так, что одно поле byte или boolean увеличивает размер объекта сразу на 4-8 байт. (Но добавление следующих 3-7 полей будут как бы «бесплатно»).