Сборка мусора (Garbage Collection)
Автоматическое освобождение памяти: среда выполнения сама находит данные, которые программе больше не нужны, и возвращает память.
Сборка мусора (garbage collection, GC) — механизм, который автоматически освобождает память. Программа постоянно создает объекты: строки, списки, ответы базы данных. Многие из них нужны лишь мгновение. В языках со сборкой мусора программист не освобождает память вручную: среда выполнения сама находит объекты, до которых программа больше не может добраться, и возвращает их память в оперативную память.
Как сборщик понимает, что объект не нужен
Основная идея — достижимость. Есть «корни»: локальные переменные выполняемых функций, глобальные переменные. Все объекты, до которых можно дойти от корней по ссылкам, живы. Остальные — мусор, даже если они ссылаются друг на друга.
- Пометка и очистка (mark and sweep). Сборщик обходит все объекты от корней, помечает живые и освобождает непомеченные.
- Поколения. Большинство объектов умирает молодыми, поэтому память делят на «молодое» и «старое» поколение и чаще чистят молодое — это быстро. Так работают сборщики Java и .NET.
- Подсчет ссылок. У каждого объекта счетчик ссылок; дошел до нуля — объект удаляется сразу. Так устроен CPython (с дополнительным сборщиком для циклических ссылок). Swift использует подсчет ссылок, расставленный компилятором (ARC), — это не сборщик мусора в строгом смысле, но цель та же.
Плата за удобство — паузы
Чтобы безопасно разобрать память, сборщику иногда нужно ненадолго остановить программу. Для пользователя это «подвисание» на десятки или сотни миллисекунд, для сервера — медленные ответы в эти моменты. Современные сборщики работают параллельно с программой: в Java по умолчанию используется G1, а ZGC держит паузы около миллисекунды даже на огромных объемах памяти. Go тоже собирает мусор параллельно с работой программы.
Языки со сборкой мусора и без
- Со сборкой мусора: Java, C#, Go, JavaScript, Python, Kotlin.
- Без нее: C и C++ (память освобождают вручную или через «умные указатели»), Rust (компилятор отслеживает владение данными и освобождает память без сборщика).
Сборщик не спасает от утечек
Если программа по-прежнему держит ссылку на ненужные данные, сборщик их не тронет. Кэш без ограничения размера, коллекция, в которую только добавляют, забытые подписки на события — частые источники утечек памяти и в языках со сборкой мусора.
На практике
Для серверных приложений на Java настраивают размер памяти и выбирают сборщик, а длительность пауз и частоту сборок выводят на графики мониторинга — например, в Prometheus и Grafana. Растущие паузы — ранний признак того, что приложению не хватает памяти или в нем есть утечка.