Сборщик мусора (Garbage Collector, GC) — автоматический механизм управления памятью в языках программирования. Вместо того чтобы разработчик вручную выделял и освобождал память (malloc/free в C), сборщик мусора периодически сканирует кучу, находит объекты без ссылок и освобождает занятую ими память.
Как работает GC
Существует несколько алгоритмов сборки мусора:
- Reference Counting — каждый объект хранит счётчик ссылок; при 0 — удаляется. Прост, но не обрабатывает циклические ссылки (PHP < 5.3, Python).
- Mark-and-Sweep — GC помечает все достижимые объекты от корней (roots), остальные удаляет. Используется в JVM (Java, Kotlin), .NET, Go.
- Generational GC — объекты делятся на поколения (young/old); молодые объекты собираются чаще. Оптимизация для факта, что большинство объектов живут недолго.
- Tri-color marking — конкурентная сборка без остановки мира (Golang, modern JVM).
PHP использует reference counting с cycle collector для циклических ссылок. Java GC (G1, ZGC, Shenandoah) — generational с конкурентной сборкой. Python — reference counting + cyclic garbage collector.
История
Garbage collection изобрёл Джон Маккарти для Lisp в 1959 году — это одно из старейших нетривиальных изобретений в программировании. Java в 1995 году сделала GC mainstream для бизнес-приложений. Долгое время GC ассоциировался с «stop-the-world» паузами — моментами, когда вся программа останавливалась для сборки. Современные GC (ZGC в Java 15+, Go 1.5+) практически устранили заметные паузы.
На что обращать внимание
GC-паузы влияют на TTFB и время ответа API. В Java-приложениях (Jenkins, Elasticsearch) GC-логи содержат информацию о паузах: -Xlog:gc*. Если паузы превышают 100 мс — стоит настроить GC или увеличить heap (-Xmx).
Утечки памяти (memory leaks) возможны даже с GC: объекты остаются в памяти, потому что на них есть ссылки, но они уже не нужны программе. Типичный случай в PHP: глобальные массивы, накапливающие данные в долгоживущих процессах (PHP-FPM воркеры). Инструменты диагностики: VisualVM (Java), Grafana + JMX Exporter для мониторинга heap.
GC и серверная производительность
В PHP GC работает автоматически, но в долгоживущих процессах (PHP-FPM, ReactPHP, Swoole) нужно понимать его поведение. PHP-FPM воркер обрабатывает N запросов и перезапускается — это prevents накопления мусора. Параметр pm.max_requests = 500 перезапускает воркер после 500 запросов, освобождая память от утечек.
В Node.js GC встроен в V8 и по умолчанию ограничен 1,5 ГБ heap (64-bit, single-process). Для memory-intensive приложений: node --max-old-space-size=4096 app.js. Превышение heap — краш процесса с «JavaScript heap out of memory». Мониторинг heap Node.js через встроенный process.memoryUsage() или метрики из Prometheus.
Для Java-приложений (Jenkins, Elasticsearch, Kafka) выбор GC алгоритма существенно влияет на throughput и latency. G1GC (Java 9+ default) — компромисс между throughput и паузами. ZGC и Shenandoah — для минимальных пауз (sub-millisecond), важно для latency-sensitive сервисов. Настройка через JVM-флаги:
# G1GC с настройками
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xms4g -Xmx4g
# ZGC (Java 15+)
-XX:+UseZGC -Xmx8g
Размер heap влияет на частоту сборки: маленький heap — частые сборки, большой — редкие, но дольше. Эмпирическое правило: оставлять свободным 50% heap для работы GC. Grafana с JMX Exporter позволяет мониторить heap utilization, количество и продолжительность GC-пауз в реальном времени.