Java, Python и Go — три модели GC
Зачем сравнивать
Сборка мусора (Garbage Collection, GC) — автоматическое освобождение памяти, занятой объектами, которые программа больше не использует. Сборщик ищет недостижимые объекты (нет цепочки ссылок от корней — стеков потоков, глобальных переменных, регистров) и возвращает их память в пул.
Во всех трёх языках цель одна, а реализация разная. Понимание модели конкретного runtime помогает объяснить паузы, утечки и выбор настроек под нагрузку.
Общая теория, утечки через «живые» ссылки, C# и детальная настройка JVM — в автоматическом управлении памятью. Ниже — сжатое сравнение Java, Python и Go в духе учебной шпаргалки GC 101.
Сводная таблица
| Java (JVM) | Python (CPython) | Go (runtime) | |
|---|---|---|---|
| Основная идея | Трассировка достижимости из корней | Подсчёт ссылок + циклический GC | Конкурентный mark-and-sweep |
| Поколения кучи | Young (Eden, Survivor) + Old; Metaspace вне heap | У gc — три поколения только для циклов; основной путь — refcount | Поколений нет — единая куча |
| Типичные паузы | От миллисекунд (G1) до субмиллисекунд (ZGC) | STW при проходе gc; refcount без паузы | Часто < 100 мкс, цель — низкая латентность |
| Настройка | -XX:+UseG1GC, -XX:+UseZGC, -Xmx | gc.set_threshold, gc.collect() | GOGC, GODEBUG=gctrace=1 |
| Практика в разделе | JVM | CPython и память | Основы Go |
Достижимость — общая схема
Во всех трёх средах «мусор» — объект, до которого нельзя дойти по ссылкам от корней.
Если вы держите ссылку в кэше, обработчике события или статическом списке — объект жив для GC, даже когда он логически не нужен. Это главный источник «утечек» при работающем сборщике — см. раздел про утечки.
Java — поколения и выбор алгоритма
Память JVM
| Область | Назначение |
|---|---|
| Heap — Young Gen | Eden + два Survivor (S0/S1); новые объекты и Minor GC |
| Heap — Old Gen | Долгоживущие объекты после нескольких сборок |
| Non-Heap — Metaspace | Метаданные классов (с Java 8 вместо PermGen) |
Гипотеза поколений: большинство объектов умирают молодыми; полный обход всей кучи нужен реже.
Эволюция сборщиков (упрощённо)
| Сборщик | Идея | Когда смотреть |
|---|---|---|
| Serial | Один поток, STW | Малые heap, встраиваемые системы |
| Parallel | Несколько потоков, упор на throughput | Пакетная обработка, допустимы редкие длинные паузы |
| CMS | Частично конкурентный mark-sweep | Устарел (удалён с JDK 14) |
| G1 | Куча регионами; сначала регионы с «мусором» | По умолчанию с JDK 9, -XX:MaxGCPauseMillis |
| ZGC | Низкие паузы, colored pointers, load barriers | Интерактивные сервисы, большие heap |
G1 и регионы
G1 делит heap на регионы фиксированного размера (обычно 1–32 МБ). Роль региона меняется:
| Метка | Роль |
|---|---|
| E (Eden) | Создание новых объектов |
| S (Survivor) | Объекты, пережившие young-сборку |
| O (Old) | Старое поколение |
Сборщик выбирает регионы с высокой долей мусора — отсюда имя Garbage-First.
Пример запуска с G1 и логом:
java -XX:+UseG1GC -Xmx4g -Xlog:gc*:file=gc.log -jar app.jar
Подробнее — JVM и сборщик мусора, настройка в статье 1 и шпаргалка JVM Options.
Python — подсчёт ссылок и циклы
Два уровня
- Reference counting — у каждого
PyObjectестьob_refcnt. Счётчик 0 → объект освобождается сразу, без отдельной «волны» GC. - Модуль
gc— mark-and-sweep для циклических ссылок (два контейнера ссылаются друг на друга, но недостижимы снаружи).
import sys
a = []
b = [a]
a.append(b) # refcount > 0 у обоих, снаружи недостижимы
del a, b
import gc
gc.collect() # разрывает цикл
Mark-and-sweep в gc
- Обход от корней (глобальные, стеки).
- Помеченные объекты — живые.
- Непомеченные — удаляются.
Три поколения (0, 1, 2) ускоряют проверку циклов: молодые контейнеры сканируют чаще. Это дополнение к refcount, а не замена поколенческой JVM-кучи.
Пулы памяти (pymalloc)
Малые объекты (< 512 байт) часто берутся из pymalloc: арены делятся на блоки в состояниях untouched, free, allocated. Крупные объекты идут в системный malloc. Пулы снижают фрагментацию и ускоряют аллокации, но долгоживущий процесс всё равно может раздувать RSS — см. архитектуру выполнения Python.
Go — конкурентный mark-and-sweep без поколений
Рантайм Go встроен в бинарник. Сборщик конкурентный: большая часть mark-and-sweep идёт параллельно с горутинами; короткие STW — на root scan и согласование фаз.
Трёхцветная разметка
| Цвет | Смысл |
|---|---|
| Белый | Ещё не просмотрен или недостижим |
| Серый | Просмотрен, дети ещё не обработаны |
| Чёрный | Просмотрен вместе с исходящими ссылками |
Корни (стек горутин, глобалы, регистры) «серые»; обход переводит объекты в чёрные; оставшиеся белые — мусор.
Гибридный write barrier
Пока mutator (ваш код) меняет указатели, collector не должен потерять живой объект. Go использует insert и delete барьеры при записи в указатели — runtime вставляет проверки при компиляции.
Поколений в Go нет: проще модель, предсказуемая настройка через GOGC (процент роста heap до следующего цикла, по умолчанию 100).
GOGC=50 ./myapp # чаще GC, меньше heap
GODEBUG=gctrace=1 ./myapp # лог циклов в stderr
Практика снижения аллокаций — sync.Pool, вынос make из циклов — в основах Go.
Как выбрать фокус обучения
| Цель | С чего начать |
|---|---|
| Сервер на JVM, тюнинг пауз | Java в этой статье → 1.md, Java → 23.md |
| Долгий Python-процесс, циклы ссылок | Python выше → 27.md |
| Микросервис на Go, GC pressure | Go выше → 13.md |
| C#, Unity, .NET | 1.md, .NET |
Краткий итог
- Java — богатый выбор GC, поколенческая heap, регионы G1, низколатентные ZGC/Shenandoah.
- Python — в первую очередь refcount;
gcловит циклы и использует поколения для этих проходов; pymalloc ускоряет мелкие объекты. - Go — один конкурентный mark-and-sweep, трёхцветная схема, write barrier, настройка
GOGC, без generational heap.
Во всех случаях GC освобождает только недостижимое; семантику «нужен / не нужен» задаёт архитектура ссылок в коде.
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Автоматическое управление памятью - как работает GC, его ограничения и корректное освобождение неуправляемых ресурсов. Краткие итоги раздела "Сборка мусора". Чек-лист раздела Сборка мусора — вопросы для самопроверки в энциклопедии Вселенная IT.Автоматическое управление памятью
Итоги
Чек-лист самопроверки