Ответ
Современные сборщики мусора в Java (на основе алгоритма mark-and-sweep и его производных) корректно удаляют объекты с циклическими зависимостями, если вся группа объектов стала недостижимой из GC Roots.
Принцип работы:
- На фазе Mark GC проходит по всем ссылкам, начиная с корней.
- Если группа объектов ссылается друг на друга, но ни на один из них нет ссылки извне этой группы (от корня), ни один объект в цикле не будет помечен как живой.
- На фазе Sweep вся циклическая структура удаляется.
Пример циклической ссылки:
class Node {
Node neighbor;
}
Node a = new Node();
Node b = new Node();
a.neighbor = b; // a ссылается на b
b.neighbor = a; // b ссылается на a (цикл)
// Ключевой момент:
a = null;
b = null;
// Теперь на внутренний цикл (a<->b) нет внешних ссылок.
// Оба объекта недостижимы и будут удалены GC.
Важно: Для корректной работы GC не требуется специальной обработки циклов. Проблема "циклических ссылок" актуальна для счетчиков ссылок (как в C++), но не для tracing-сборщиков (как в Java), которые отслеживают достижимость от корней.