Как оценить размер в памяти, занимаемый ссылочным типом данных и объектом в Java?

«Как оценить размер в памяти, занимаемый ссылочным типом данных и объектом в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Размер в памяти складывается из самой ссылки и объекта, на который она указывает. Точный размер зависит от JVM, версии Java и платформы.

1. Размер ссылки (переменной):

  • Обычно 4 байта (32-битная JVM) или 8 байт (64-битная JVM).
  • В современных 64-битных JVM часто используется технология Compressed Oops (обычно включена по умолчанию), которая «сжимает» ссылки до 4 байт для кучи до ~32 ГБ, что экономит память.

2. Размер объекта в куче: Минимальный размер объекта включает:

  • Заголовок объекта (object header): Обычно 12 байт (8 байт для марк-слова + 4 байта для ссылки на класс). При включенных Compressed Oops. Без них — 16 байт.
  • Поля объекта: Примитивные типы (int – 4 байта, long – 8 и т.д.) и ссылки на другие объекты (по правилам из пункта 1).
  • Выравнивание (padding): JVM выравнивает размер объекта до кратного 8 байт для оптимизации доступа.

Пример оценки:

class SimpleObject {
    private int id;          // 4 байта
    private String name;     // ссылка: 4 байта (с Compressed Oops)
}
// Примерный расчет размера экземпляра SimpleObject:
// Заголовок: 12 байт
// Поле int id: 4 байта
// Поле-ссылка String name: 4 байта
// ИТОГО: 20 байт -> Выравнивание до 24 байт.

Как измерить точно (для отладки): Используйте инструментальный API java.lang.instrument.Instrumentation.

import java.lang.instrument.Instrumentation;

public class SizeAgent {
    private static Instrumentation inst;
    // Агент должен быть собран в JAR с premain-методом
    public static void premain(String args, Instrumentation instArg) {
        inst = instArg;
    }
    public static long getObjectSize(Object o) {
        return inst.getObjectSize(o);
    }
}
// Вызов getObjectSize() вернет размер объекта + заголовок, но без учета вложенных объектов.

Для массивов: К базовому размеру объекта добавляется 4 байта для хранения длины и память для каждого элемента.