Как сборщик мусора Java обрабатывает циклические ссылки между объектами?

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

Ответ

Сборщик мусора (Garbage Collector, GC) успешно удаляет объекты, связанные циклическими ссылками, если на них больше нет ссылок из так называемых "корневых" (GC Roots) объектов.

Принцип работы: Основные алгоритмы GC (Mark-Sweep, G1, ZGC) используют фазу marking (пометка), в которой они обходят граф объектов, начиная с корней (например, активные потоки, статические поля, локальные переменные в стеке). Объекты, достижимые из корней, помечаются как живые. Недостижимые объекты, даже если они ссылаются друг на друга, остаются непомеченными и удаляются на фазе sweeping (очистка).

Пример циклической ссылки и сборки мусора:

class Node {
    Node reference;
}

// Создаем два объекта со взаимной ссылкой
Node nodeA = new Node();
Node nodeB = new Node();
nodeA.reference = nodeB;
nodeB.reference = nodeA;

// Обрываем внешние ссылки на объекты
nodeA = null;
nodeB = null;

// На этом этапе объекты Node недостижимы из корней.
// Несмотря на циклическую ссылку между ними, GC удалит оба объекта.

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