Как оценить объем памяти, занимаемый объектом String в Java?

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

Ответ

Размер объекта String складывается из размера самого объекта и внутреннего массива для хранения символов. Оценка зависит от реализации JVM (особенно с Java 9 и компактированием строк).

Базовая структура (до Java 8):

  1. Объект String: заголовок объекта (16 байт на 64-битной JVM со сжатыми ссылками) + поля (char[] value, int hash, int hash32 и др.) ≈ 24-32 байта.
  2. Внутренний массив char[]: заголовок массива (16 байт) + 2 байта на каждый символ (UTF-16).
  3. Выравнивание (padding): JVM округляет общий размер до кратного 8 байтам.

Пример расчета для строки "Hello" (5 символов):

  • Объект String: ~24 байта.
  • Массив char[5]: 16 байт (заголовок) + 5 * 2 = 10 байт (данные) = 26 байт → округляется до 32 байт.
  • Итого: ~56 байт.

Важные изменения с Java 9+:

Введена оптимизация Compact Strings. Если строка содержит только Latin-1 символы (код <= 255), используется массив byte[] (1 байт на символ).

  • Для "Hello" (только Latin-1):
    • Объект String: ~24 байта.
    • Массив byte[5]: 16 + 5 = 21 байт → округляется до 24 байт.
    • Итого: ~48 байт (экономия ~8 байт).

Как измерить точно?

Используйте инструменты или библиотеки:

  • JOL (Java Object Layout):

    // Добавьте зависимость org.openjdk.jol:jol-core
    import org.openjdk.jol.vm.VM;
    import org.openjdk.jol.info.ClassLayout;
    
    String str = "Hello";
    System.out.println(ClassLayout.parseInstance(str).toPrintable());
  • Профилировщики памяти (VisualVM, YourKit, JProfiler).

Вывод: Для грубой оценки ASCII/Latin-1 строки можно использовать формулу: ~40 + 2 * n (Java 8) или ~40 + 1 * n (Java 9+), где n — количество символов.