Избавляемся от мусора в Java

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

В преддверии старта курса «Подготовка к сертификации Oracle Java Programmer (OCAJP)» подготовили перевод полезного материала. Предлагаем также посмотреть запись демо-занятия «Конструкторы и блоки инициализации».


Что такое сборка мусора, зачем она нужна и как работает

Для работы любого приложения требуется память. Однако память компьютера ограничена. Поэтому важно ее очищать от старых неиспользуемых данных, чтобы освободить место для новых.

Кто занимается этой очисткой? Как и когда очищается память? Как выглядит структура памяти? Давайте разберем с этим подробнее.

Структура памяти Java

Память в Java состоит из следующих областей:

Структура памяти Java
Структура памяти Java

Native Memory — вся доступная системная память.

Heap (куча) — часть native memory, выделенная для кучи. Здесь JVM хранит объекты. Это общее пространство для всех потоков приложения. Размер этой области памяти настраивается с помощью параметра -Xms (минимальный размер) и -Xmx (максимальный размер).

Stack (стек) — используется для хранения локальных переменных и стека вызовов метода. Для каждого потока выделяется свой стек.

Metaspace (метаданные) — в этой памяти хранятся метаданные классов и статические переменные. Это пространство также является общими для всех. Так как metaspace является частью native memory, то его размер зависит от платформы. Верхний предел объема памяти, используемой для metaspace, можно настроить с помощью флага MaxMetaspaceSize.

PermGen (Permanent Generation, постоянное поколение) присутствовало до Java 7. Начиная с Java 8 ему на смену пришла область Metaspace.

CodeCache (кэш кода) — JIT-компилятор компилирует часто исполняемый код, преобразует его в нативный машинный код и кеширует для более быстрого выполнения. Это тоже часть native memory.

Сборка мусора: введение

Что такое "мусор"? Мусором считается объект, который больше не может быть достигнут по ссылке из какого-либо объекта. Поскольку такие объекты больше не используются в приложении, то их можно удалить из памяти.

Например, на диаграмме ниже объект fruit2 может быть удален из памяти, поскольку на него нет ссылок.

Мусор
Мусор

Что такое сборка мусора? Сборка мусора — это процесс автоматического управления памятью. Освобождение памяти (путем очистки мусора) выполняется автоматически специальным компонентом JVM — сборщиком мусора (Garbage Collector, GC). Нам, как программистам, нет необходимости вмешиваться в процесс сборки мусора.

Источник: Oracle.com
Источник: Oracle.com

Сборка мусора: процесс

Для сборки мусора используется алгоритм пометок (Mark & Sweep). Этот алгоритм состоит из трех этапов:

  1. Mark (маркировка). На первом этапе GC сканирует все объекты и помечает живые (объекты, которые все еще используются). На этом шаге выполнение программы приостанавливается. Поэтому этот шаг также называется "Stop the World" .

  2. Sweep (очистка). На этом шаге освобождается память, занятая объектами, не отмеченными на предыдущем шаге.

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

Mark & Sweep GC
Mark & Sweep GC

Поколения объектов

Что такое поколения объектов?

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

  1. Young Generation (молодое поколение). Здесь создаются новые объекты. Область young generation разделена на три части раздела: Eden (Эдем), S0 и S1 (Survivor Space — область для выживших).

  2. Old Generation (старое поколение). Здесь хранятся давно живущие объекты.

Поколения в куче
Поколения в куче

Что такое Stop the World?

Когда запускается этап mark, работа приложения останавливается. После завершения mark приложение возобновляет свою работу. Любая сборка мусора — это "Stop the World".

Что такое гипотеза о поколениях?

Как уже упоминалось ранее, для оптимизации этапов mark и sweep используются поколения. Гипотеза о поколениях говорит о следующем:

  1. Большинство объектов живут недолго.

  2. Если объект выживает, то он, скорее всего, будет жить вечно.

  3. Этапы mark и sweep занимают меньше времени при большом количестве мусора. То есть маркировка будет происходить быстрее, если анализируемая область небольшая и в ней много мертвых объектов.

Таким образом, алгоритм сборки мусора, использующий поколения, выглядит следующим образом:

Сборка мусора поколениями
Сборка мусора поколениями
  1. Новые объекты создаются в области Eden. Области Survivor (S0, S1) на данный момент пустые.

  2. Когда область Eden заполняется, происходит минорная сборка мусора (Minor GC). Minor GC — это процесс, при котором операции mark и sweep выполняются для young generation (молодого поколения).

  3. После Minor GC живые объекты перемещаются в одну из областей Survivor (например, S0). Мертвые объекты полностью удаляются.

  4. По мере работы приложения пространство Eden заполняется новыми объектами. При очередном Minor GC области young generation и S0 очищаются. На этот раз выжившие объекты перемещаются в область S1, и их возраст увеличивается (отметка о том, что они пережили сборку мусора).

  5. При следующем Minor GC процесс повторяется. Однако на этот раз области Survivor меняются местами. Живые объекты перемещаются в S0 и у них увеличивается возраст. Области Eden и S1 очищаются.

  6. Объекты между областями Survivor копируются определенное количество раз (пока не переживут определенное количество Minor GC) или пока там достаточно места. Затем эти объекты копируются в область Old.

  7. Major GC. При Major GC этапы mark и sweep выполняются для Old Generation. Major GC работает медленнее по сравнению с Minor GC, поскольку старое поколение в основном состоит из живых объектов.

Преимущества использования поколений

Minor GC происходит в меньшей части кучи (~ 2/3 от кучи). Этап маркировки эффективен, потому что область небольшая и состоит в основном из мертвых объектов.

Недостатки использования поколений

В каждый момент времени одно из пространств Survivor (S0 или S1) пустое и не используется.

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

В этом разделе приведены некоторые важные флаги, которые можно использовать для настройки процесса сборки мусора.

Флаг

Описание

-Xms

Первоначальный размер кучи

-Xmx

Максимальный размер куча

-XX:NewRatio=n

Отношение размера Old Generation к Young Generation

-XX:SurvivorRatio=n

Отношение размера Eden к Survivor

-XX:MaxTenuringThreshold=n

Возраст объекта, когда объект перемещается из области Survivor в область Old Generation

Флаги JVM

Типы сборщиков мусора

Сборщик мусора

Описание

Преимущества

Когда использовать

Флаги для включения

Serial

Использует один поток.

Эффективный, т.к. нет накладных расходов на взаимодействие потоков.

Однопроцессорные машины.

Работа с небольшими наборами данных.

-XX:+UseSerialGC

Parallel

Использует несколько потоков.

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

В приоритете пиковая производительность.

Допустимы паузы при GC в одну секунду и более.

Работа со средними и большими наборами данных.

Для приложений, работающих на многопроцессорном или многопоточном оборудовании.

-XX:+UseParallelGC

G1

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

Может использоваться как на небольших системах, так и на больших с большим количеством процессоров и большим количеством памяти.

Когда время отклика важнее пропускной способности.

Паузы GC должны быть меньше одной секунды.

-XX:+UseG1GC

Z1

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

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

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

+UseZGC

Сборщики мусора в Java

Инструменты мониторинга GC

Что мониторить?

  1. Частота запуска сборки мусора. Так как GC вызывает "stop the world", поэтому чем время сборки мусора меньше, тем лучше.

  2. Длительность одного цикла сборки мусора.

Как мониторить сборщик мусора?

Для мониторинга можно использовать следующие инструменты:

  1. Visual VM (https://visualvm.github.io/)

  2. Для включения логирования событий сборщика мусора добавьте следующие параметры JVM:

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

Логи GC выглядят следующим образом:

[15,651s][info ][gc] GC(36) Pause Young (G1 Evacuation Pause) 239M->57M(307M) (15,646s, 15,651s) 5,048ms

Объяснение:

[Время старта приложения = 15,651s]

[Уровень сообщения = info]

[Тег = gc]

[Тип GC = Pause Young] 

[Причина запуска GC = G1 Evacuation Pause] 

[Информация о потреблении памяти : "занято до GC" = 239M -> "занято после GC" = 57M (Размер кучи = 307M)] 

[Время начала и окончания GC = 15,646s, 15,651s] 

[Общее время GC = 5,048ms]

Логи GC удобно анализировать с помощью gcEasy.io

Ссылки

  • https://docs.oracle.com/en/java/javase/15/gctuning/

  • https://www.oracle.com/webfolder/technetwork/tutorials/mooc/JVM_Troubleshooting/week1/lesson1.pdf

  • https://sergiomartinrubio.com/articles/java-memory-model-overview


Узнать подробнее о курсе «Подготовка к сертификации Oracle Java Programmer (OCAJP)»

Смотреть запись демо-занятия «Конструкторы и блоки инициализации»

Источник: https://habr.com/ru/company/otus/blog/553996/


Интересные статьи

Интересные статьи

Доброго времени суток, друзья! Когда речь заходит об изучении JavaScript, будь то первое знакомство с языком или углубление имеющихся знаний, найти в «интернетах» теоретические ма...
Проблема Одной из проблем Java является ее многословность и объем необходимого стандартного кода. Это общеизвестно. Давайте рассмотрим простой класс Cat на Java. Мы хотим, чтобы каждый объект C...
Компании растут и меняются. Если для небольшого бизнеса легко прогнозировать последствия любых изменений, то у крупного для такого предвидения — необходимо изучение деталей.
Вы когда-нибудь задумывались, как браузеры читают и исполняют JavaScript-код? Это выглядит таинственно, но в этом посте вы можете получить представление, что же происходит под капотом. Начнё...
Всем привет. Все меньше времени остается до запуска курса «Безопасность информационных систем», поэтому сегодня мы продолжаем делиться публикациями, приуроченными к запуску данного курса. Кстати,...