Короткий ответ
Garbage Collector автоматически управляет памятью кучи: он находит объекты, которые больше не нужны программе, и освобождает занимаемую ими память. Мусором считается объект, до которого нельзя добраться по цепочке ссылок от корней GC (GC Roots). Современные JVM используют трассирующие (tracing) алгоритмы, а не подсчёт ссылок (reference counting), из-за проблемы циклических ссылок.
Как это работает подробнее
Reference counting — исторический подход: у каждого объекта ведётся счётчик ссылок; когда он уменьшается до нуля, объект удаляется сразу. Минус — не справляется с циклическими ссылками: если A ссылается на B, а B на A, и извне ссылок нет, счётчики не обнуляются и память утекает.
Tracing-сборщик стартует от корней GC (локальные переменные потоков, статические поля и т. д.) и обходит граф объектов, помечая (mark) все достижимые. Всё непомеченное считается мусором и удаляется (sweep), при необходимости выполняется уплотнение (compact) против фрагментации.
- Для скорости куча делится на поколения: новые объекты появляются в молодом поколении (Eden и survivor-области), где сборки частые и быстрые (Minor GC), а пережившие несколько сборок продвигаются в старое поколение.
- Пауза, во время которой приложение останавливается для сборки, называется stop-the-world; разные сборщики минимизируют её по-разному.
Что использовать на практике
- Проектируйте граф объектов так, чтобы мусор быстро становился недостижимым — это снижает нагрузку на GC.
- Следите за утечками: объект, оставшийся достижимым (например, в статической коллекции), не будет собран.
- Выбирайте сборщик под требования по паузам и пропускной способности: Serial, Parallel, G1 или ZGC.