Ответ 1
Это полностью зависит от реализации, но есть несколько факторов, которые влияют на размер объекта в Java.
Во-первых, количество и типы полей в объекте Java определенно влияют на использование пространства, поскольку для хранения всех полей объекта требуется как минимум столько места для хранения. Однако из-за оптимизации сжатия, выравнивания и оптимизации указателя нет прямой формулы, которую вы можете использовать, чтобы точно вычислить, сколько пространства используется таким образом.
Что касается методов, как правило, количество методов в объекте не влияет на его размер. Методы часто реализуются с использованием функции таблицы виртуальных функций (или "vtables" ), которые позволяют вызывать методы с помощью ссылки базового класса в константах время. Эти таблицы обычно сохраняются при наличии одного экземпляра виртуальной таблицы, разделяемого несколькими объектами, а затем каждый объект хранит единственный указатель на таблицу vtable.
Методы интерфейса немного усложняют этот снимок, так как возможны несколько различных реализаций. Одна реализация добавляет новый указатель vtable для каждого интерфейса, поэтому количество реализованных интерфейсов может влиять на размер объекта, а другие нет. Опять же, реализация зависит от того, как вещи фактически собраны в памяти, поэтому вы не можете точно знать, будет ли это иметь стоимость памяти.
Насколько я знаю, в настоящее время не существует реализаций JVM, в которых длина метода влияет на размер объекта. Как правило, в памяти сохраняется только одна копия каждого метода, а затем код передается по всем экземплярам определенного объекта. Использование более длинных методов может потребовать более полной памяти, но не должно влиять на память каждого объекта для экземпляров класса. Тем не менее, спецификация JVM не делает promises, что это должно быть так, но я не могу придумать разумную реализацию, которая бы потратила дополнительное пространство на объект для кода метода.
В дополнение к полям и методам многие другие факторы могут способствовать размеру объекта. Вот несколько:
В зависимости от типа сборщика мусора (или сборщика), который использует JVM, каждый объект может иметь дополнительное пространство для хранения информации о том, жив ли объект, мертв, доступен и т.д. Это может увеличить пространство для хранения, но это не под вашим контролем. В некоторых случаях JVM может оптимизировать размеры объектов, пытаясь сохранить объект в стеке вместо кучи. В этом случае служебные данные могут даже не присутствовать для некоторых типов объектов.
Если вы используете синхронизацию, у объекта может быть выделено дополнительное пространство, чтобы он мог быть синхронизирован. Некоторые реализации JVM не создают монитор для объекта до тех пор, пока он не понадобится, поэтому вы можете получить меньшие объекты, если вы не используете синхронизацию, но вы не можете гарантировать, что это будет так.
Кроме того, для поддержки таких операторов, как instanceof
и typecasting, каждый объект может иметь некоторое пространство, зарезервированное для хранения информации типа. Как правило, это связано с объектом vtable, но нет гарантии, что это будет правдой.
Если вы используете утверждения, некоторые реализации JVM создадут в вашем классе поле, содержащее, включены ли утверждения. Затем это используется для отключения или включения утверждений во время выполнения. Опять же, это специфично для реализации, но хорошо иметь в виду.
Если ваш класс является нестатическим внутренним классом, ему может потребоваться ссылка на класс, который содержит его, чтобы он мог получить доступ к своим полям. Однако JVM может оптимизировать это, если вы никогда не воспользуетесь этим.
Если вы используете анонимный внутренний класс, у класса может потребоваться дополнительное пространство для хранения переменных final
, которые видны в его охватывающей области, чтобы они могли ссылаться внутри класса. Это специфичная для реализации информация о том, скопирована ли эта информация в поля класса или просто локально хранится в стеке, но она может увеличить размер объекта.
В некоторых реализациях Object.hashCode()
или System.identityHashCode(Object)
может потребоваться дополнительная информация, которая будет храниться в каждом объекте, который содержит значение этого хеш-кода, если он не может вычислить его каким-либо другим способом (например, если объект может быть перемещается в память). Это может увеличить размер каждого объекта.