Ответ
Сборщик мусора (GC) в Go — это параллельный, трехцветный сборщик мусора с алгоритмом "mark-and-sweep" (пометь и собери), спроектированный для минимизации задержек (пауз "Stop The World").
Основные принципы:
- Параллельность: GC работает одновременно с выполнением основной программы (горутинами), используя доступные процессорные ядра, чтобы минимизировать время пауз.
- Трехцветный алгоритм: Объекты в памяти условно делятся на три цвета:
- Белые: Кандидаты на удаление. Изначально все объекты белые.
- Серые: Достижимые объекты, но их дочерние объекты еще не просканированы. Это "очередь на сканирование".
- Черные: Достижимые объекты, все дочерние объекты которых также просканированы. Эти объекты точно не будут удалены в текущем цикле.
- Non-generational (Без поколений): В отличие от GC в Java или .NET, GC в Go не разделяет объекты на "молодые" и "старые" поколения. Это упрощает сам GC, но может приводить к большему объему работы на каждом цикле.
Фазы работы GC:
- Mark Setup (Настройка маркировки) - STW: Короткая пауза "Stop The World" (STW), во время которой включается барьер записи (write barrier). Барьер отслеживает все изменения указателей, чтобы GC не пропустил новые связи между объектами.
- Marking (Маркировка) - Конкурентно: Основная фаза. GC сканирует стеки горутин, глобальные переменные и помечает все достижимые объекты как серые. Затем он итеративно проходит по серым объектам, помечая их дочерние объекты и переводя родительский объект в черный цвет. Эта фаза выполняется параллельно с работой приложения.
- Mark Termination (Завершение маркировки) - STW: Вторая короткая пауза STW. GC завершает маркировку, обрабатывая оставшиеся объекты. После этой фазы все достижимые объекты — черные, а недостижимые — белые.
- Sweeping (Очистка) - Конкурентно: GC проходит по памяти и освобождает все белые (недостижимые) объекты. Эта фаза также выполняется параллельно.
Управление и тюнинг:
GOGC
: Переменная окружения, которая контролирует, когда запускать следующий цикл GC.GOGC=100
(значение по умолчанию) означает, что GC запустится, когда объем новой выделенной памяти достигнет 100% от объема живой памяти после предыдущего цикла.runtime.GC()
: Позволяет принудительно запустить цикл сборки мусора.