Память

Основные разделы

Class Loader Subsystem

JVM загружает классы с помощью системы загрузчиков (Class Loaders), которая реализует модель делегирования:

Типы памяти

Вся область памяти называется Native Memory

PermGen(Permanent Generation) (deprecated)

С Java 8 ему на смену пришла область Metaspace.

Metaspace

Описание

  1. Является общими для всех.
  2. MaxMetaspaceSize - макс размер.

Здесь хранятся

  1. Структура класса
  2. bytecode методов
  3. Сигнатуры полей
  4. constant pool
  5. Информация о методах

CodeCache(кэш кода)

JIT - компилятор компилирует часто исполняемый код, преобразует его в нативный машинный код и кеширует для более быстрого выполнения.

Heap(куча)

Heap
├── Young Generation - вновь созданные объекты.
│   ├── Eden Space - вновь созданные объекты.
│   └── Survivor Spaces (S0, S1) - те, кто “выжил” после первой сборки.
└── Old Generation (Tenured) - объекты, пережившие несколько сборок, считаются “долгоживущими”.
        

Описание

  1. Используется Java Runtime для выделения памяти и хранения объектов и JRE классов.
  2. Здесь работает Garbage Collector: освобождает память путем удаления объектов, на которые нет каких-либо ссылок.
  3. Любой объект, созданный в куче, имеет глобальный доступ и на него могут ссылаться с любой части приложения.
  4. Доступно для всех потоков.
  5. Для JVM мы можем задать начальный пул выделения памяти (Xms) и максимальный пул выделения памяти (Xmx).
  6. Если куча переполнена получаем OutOfMemoryError.

Здесь хранятся

  1. При запуске программы сюда загружаются все классы среды выполнения
  2. Objects
  3. Object fields(включая примитивные)
  4. Static fields
  5. Pool String

Stack

Описание

Каждый поток, работающий в виртуальной машине Java, имеет свой собственный стек.

  1. Всякий раз, когда вызывается метод, в памяти стека создается новый блок, и после его завершения удаляется вместе с переменными(LIFO).
  2. Размер стековой памяти намного меньше объема памяти в куче.
  3. Используется только одним потоком.
  4. Для JVM мы можем задать максимальный пул стековой памяти(Xss).
  5. Если память стека переполнена получаем StackOverflowError.

Здесь хранятся

  1. Stack вызова методов.
  2. Локальные(внутри методов) примитивы.
  3. Ссылки на локальные объекты(которые хранятся в heap).

Garbage Collector

Мусор - object в Heap на которого никто не ссылается.

Алгоритм работы GC: по фазам

Типы сборок:

Алгоритм сборки мусора, использующий поколения

  1. Новые объекты создаются в EDEN.
  2. Когда область Eden заполняется, происходит минорная сборка мусора (Minor GC). Minor GC — mark и sweep выполняются для young generation.
  3. Живые объекты перемещаются в одну из областей Survivor (например, S0).
  4. При следующем Minor GC процесс повторяется. Но объекты в областях S0 и S1 меняются метами, увеличивая свой возраст.
  5. Объекты между областями Survivor копируются определенное количество раз (пока не переживут определенное количество Minor GC) или пока там достаточно места. Затем эти объекты копируются в область Old.
  6. Major GC - этапы mark и sweep выполняются для Old Generation. Major GC работает медленнее по сравнению с Minor GC, поскольку старое поколение в основном состоит из живых объектов.

Как GC определяет, что объект мёртв?

GC не использует reference count. Он строит граф достижимости:

Сборка мусора: флаги

Включение логов GC

-XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -
Xloggc:/tmp/[Application-Name]-[Application-port]-%t-gc.log -
XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=20 -
XX:GCLogFileSize=100M
        

Виды Garbage Collector(сборщик мусора)

  1. Serial GC - S GC

    Один поток. Просто и медленно.

    -XX:+UseSerialGC

  2. Parallel GC - P GC

    Несколько потоков.

    Многопоточность ускоряет сборку мусора.

    Высокая пропускная способность.

    -XX:+UseParallelGC

  3. CMS Garbage Collector - CMS GC
  4. G1 GC - G1 GC

    Выполняет некоторую тяжелую работу параллельно с работой приложения.

    -XX:+UseG1GC

  5. The Z GC - ZGC

    Выполняет всю тяжелую работу параллельно с работой приложения.

    В приоритете время отклика.

    Работает с огромными кучами(до терабайта).

    Низкая задержка.

    -XX:+UseZGC

Немного примеров настройки GC

Настроить GC для веб-серверного приложения, где приоритетом является минимизация времени остановки для низкой задержки.

java -XX:+UseG1GC -Xms4G -Xmx4G -XX:MaxGCPauseMillis=200 -jar my-web-app.jar

Настроить GC для приложения обработки больших данных, где важна общая пропускная способность и эффективность использования памяти.

java -XX:+UseParallelGC -Xms8G -Xmx8G -XX:ParallelGCThreads=8 -jar my-data-processing-app.jar

Настроить GC для настольного приложения с пользовательским интерфейсом, требующего коротких пауз GC для обеспечения плавности работы.

java -XX:+UseConcMarkSweepGC -Xms512M -Xmx512M -jar my-desktop-app.jar

Настроить GC для сервера приложений, обрабатывающего высокие нагрузки и требующего большого объема памяти и высокой пропускной способности.

java -XX:+UseG1GC -Xms16G -Xmx16G -XX:ConcGCThreads=10 -jar my-high-load-server-app.jar

Настроить GC для приложения с критически важными требованиями к низкой задержке.

java -XX:+UseZGC -Xms4G -Xmx4G -jar my-low-latency-app.jar

Советы по оптимизации

Garbage Collector by default.

  1. Java 7 - Parallel GC
  2. Java 8 - Parallel GC
  3. Java 9 - G1 GC
  4. Java 10 - G1 GC
  5. Java 11 - Z GC

Memory leak

Memory leak - объект уже не нужен, но GC не может его удалить, потому что на него осталась ссылка. То есть память логически свободна, но технически занята.

Как найти memory leak

Вопросы

System.gc() - метод для выполнения сбора мусора. Но JVM сама решить запускать или нет.

finalize() - вызывается перед удалением объекта. С Java 9 не рекомендуем к использованию.

Happens-Before

Happens-before - правило из Java Memory Model(JMM), которое определяет, когда изменения одного потока гарантированно видны другому потоку.

Если действие A happens-before B, то: A выполнится раньше B. Все изменения памяти, сделанные в A, будут видны в B.

Happens-before = гарантия видимости + гарантия порядка.

Основные правила happens-before

Типы ссылок в java

Strong Reference(сильная ссылка)

Object obj = new Object();

Soft Reference(мягкая ссылка)

SoftReference<Object> ref = new SoftReference<>(new Object());

Weak Reference(слабая ссылка)

WeakReference<Object> ref = new WeakReference<>(new Object());

Phantom Reference(фантомная ссылка)

PhantomReference<Object> ref = new PhantomReference<>(new Object(), referenceQueue);