Подтвердить что ты не робот

Что определяет размер объекта Java?

Что способствует размеру одного объекта в памяти?

Я знаю, что примитивы и ссылки будут, но есть ли что-нибудь еще? Будет ли количество методов и их длина?

4b9b3361

Ответ 1

Это полностью зависит от реализации, но есть несколько факторов, которые влияют на размер объекта в Java.

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

Что касается методов, как правило, количество методов в объекте не влияет на его размер. Методы часто реализуются с использованием функции таблицы виртуальных функций (или "vtables" ), которые позволяют вызывать методы с помощью ссылки базового класса в константах время. Эти таблицы обычно сохраняются при наличии одного экземпляра виртуальной таблицы, разделяемого несколькими объектами, а затем каждый объект хранит единственный указатель на таблицу vtable.

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

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

В дополнение к полям и методам многие другие факторы могут способствовать размеру объекта. Вот несколько:

В зависимости от типа сборщика мусора (или сборщика), который использует JVM, каждый объект может иметь дополнительное пространство для хранения информации о том, жив ли объект, мертв, доступен и т.д. Это может увеличить пространство для хранения, но это не под вашим контролем. В некоторых случаях JVM может оптимизировать размеры объектов, пытаясь сохранить объект в стеке вместо кучи. В этом случае служебные данные могут даже не присутствовать для некоторых типов объектов.

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

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

Если вы используете утверждения, некоторые реализации JVM создадут в вашем классе поле, содержащее, включены ли утверждения. Затем это используется для отключения или включения утверждений во время выполнения. Опять же, это специфично для реализации, но хорошо иметь в виду.

Если ваш класс является нестатическим внутренним классом, ему может потребоваться ссылка на класс, который содержит его, чтобы он мог получить доступ к своим полям. Однако JVM может оптимизировать это, если вы никогда не воспользуетесь этим.

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

В некоторых реализациях Object.hashCode() или System.identityHashCode(Object) может потребоваться дополнительная информация, которая будет храниться в каждом объекте, который содержит значение этого хеш-кода, если он не может вычислить его каким-либо другим способом (например, если объект может быть перемещается в память). Это может увеличить размер каждого объекта.

Ответ 2

Чтобы добавить немного (по общему признанию, смутных) данных в @templatetypedef отличный ответ. Эти номера предназначены для типичных 32-разрядных JVM-версий, но они специфичны для реализации:

  • Накладные расходы заголовка для каждого объекта обычно 2 слова для обычного объекта и 3 слова для массива. Заголовок включает в себя связанные с GC флаги и некоторый указатель на фактический класс объекта. Для массива требуется дополнительное слово для хранения размера массива.

  • Если вы вызывали (прямо или косвенно) System.identityHashCode() на объект, и он пережил цикл GC, добавьте дополнительное слово, чтобы сохранить значение хэш-кода. (Современные JVM используют умный трюк, чтобы избежать резервирования поля заголовка hashcode для всех объектов...)

  • Гранулярность распределения хранилища может быть кратной словам; например 2.

  • Поля объекта обычно выравниваются по слову; то есть они не упакованы.

  • Элементы массива примитивного типа упаковываются, но булевы обычно представляются байтом в упакованной форме.

  • Ссылки занимают 4 байта как в виде полей, так и в виде элементов массива.

Для 64-разрядных JVM-вещей немного сложнее из-за сжатия указателей (OOPS) в некоторых JVM. Кроме того, я не уверен, что поля 32 или 64 бит выровнены.


(Примечание: вышесказанное основано на том, что я слышал/читал в разных местах от разных "знающих людей". Нет никакого определенного источника для такого рода информации, кроме Oracle/Sun, и (AFAIK) "ничего не опубликовано".)

Ответ 4

AFAIK, в исходном коде HBase, существует некоторая caculation о размере объекта, основанная на некоторых общих известных правилах, как разные поля занимают пробелы. И это будет отличаться в 32-битной или 64-битной ОС. По крайней мере, выше всех людей. Но я не задумывался над тем, почему они это делают. Но они действительно сделали это в исходном коде.

Кроме того, класс Java.lang.intrument.Intrumentation может сделать это также с помощью getObjectSize(). Я предполагаю, что проект с открытым исходным кодом также основан на нем. В этой ссылке есть сведения о том, как ее использовать. В Java, каков наилучший способ определить размер объекта?

В качестве комментария. На самом деле меня тоже интересует, если вы сделаете это в исходном коде, какой будет наиболее значимый вариант использования?