Как работает сборка мусора

GC освобождает память объектов, которые больше не достижимы от корней. JVM не считает ссылки; она обходит граф объектов.

Типичные GC roots:

  • локальные переменные и параметры активных стеков;
  • статические поля загруженных классов;
  • активные потоки;
  • JNI-ссылки и внутренние структуры JVM.
Node first = new Node();
Node second = new Node();
first.next = second;
second.next = first;
 
first = null;
second = null; // цикл недостижим и может быть собран

Циклические ссылки не мешают tracing collector: важен путь от GC root.

Основные операции

  1. mark — определить живые объекты;
  2. sweep — освободить участки мёртвых;
  3. compact или evacuate — переместить живые объекты и убрать фрагментацию;
  4. update references — исправить ссылки после перемещения.

Конкретный сборщик сочетает эти операции, часть выполняет конкурентно с приложением, часть — во время stop-the-world паузы.

Поколения

Большинство объектов живёт недолго, поэтому heap часто делят на young и old. Новые объекты обычно появляются в Eden/TLAB; пережившие сборки могут перемещаться или продвигаться в old. Межпоколенные ссылки отслеживаются специальными структурами, чтобы не сканировать весь heap при каждой young collection.

Термины Minor, Major и Full GC не стандартизованы одинаково для всех collectors. Нельзя выводить причину паузы только из названия: нужны GC logs и документация выбранного алгоритма.

Что влияет на приложение

  • allocation rate и объём живого графа;
  • размер heap;
  • крупные объекты;
  • количество ссылок между регионами;
  • требования к latency и throughput;
  • ошибочное удержание объектов — memory leak возможен и в Java.

System.gc() — просьба, а не гарантия. Финализаторы также не дают гарантии.

На собеседовании

Соберёт ли GC цикл объектов? Да, если цикл недостижим от roots.

Все ли фазы concurrent? Нет; даже concurrent collectors имеют короткие STW-фазы.

Что важнее количества созданных объектов? Скорость выделения, объём выживших данных и требования к паузам.

Почему Java-приложение может течь? Достижимая коллекция, listener, cache или ThreadLocal продолжает удерживать ненужные объекты.

Связано: Сборщики мусора в Java, Garbage collector, Виды ссылок в java, Стек и куча в Java.