Опишите принципы работы сборщика мусора (Garbage Collector) в Go.

Ответ

Сборщик мусора (GC) в Go — это конкурентный (concurrent), не-генерационный сборщик, использующий алгоритм маркировки и очистки с трехцветной разметкой (tricolor mark-and-sweep). Его главная цель — минимизация пауз (stop-the-world) для достижения низкой задержки (low latency) в приложениях.

Ключевые принципы:

  1. Трехцветный алгоритм: Все объекты в куче делятся на три множества:

    • Белые (White): Потенциальный мусор. В начале цикла все объекты белые.
    • Серые (Gray): Достижимые объекты, но их дочерние объекты еще не просканированы. Это "фронт" работы для GC.
    • Черные (Black): Достижимые объекты, все дочерние объекты которых также просканированы.

  2. Конкурентность: Основная работа по маркировке (сканирование графа объектов) происходит конкурентно, то есть параллельно с выполнением горутин вашего приложения. Это позволяет избежать долгих пауз.



  3. Write Barrier (Барьер записи): Специальный механизм, который включается во время работы GC. Если горутина изменяет указатель, например, черный объект начинает ссылаться на белый, барьер записи перекрашивает белый объект в серый. Это гарантирует, что GC не пропустит живой объект.


Этапы работы (упрощенно):

  1. Mark Setup (Подготовка к маркировке): Короткая пауза (STW), во время которой включается барьер записи.
  2. Marking (Маркировка): GC сканирует граф объектов, начиная с корней (глобальные переменные, стеки горутин), и перекрашивает объекты из белых в серые, а затем в черные. Этот этап выполняется конкурентно.
  3. Mark Termination (Завершение маркировки): Вторая короткая пауза (STW) для завершения маркировки и отключения барьера записи.
  4. Sweeping (Очистка): Память, занятая белыми (недостижимыми) объектами, освобождается. Этот этап также выполняется конкурентно.

Управление:

  • Переменная окружения GOGC (по умолчанию 100) контролирует, когда запускается следующий цикл GC. GOGC=100 означает, что GC запустится, когда размер кучи достигнет 200% от размера живых объектов после предыдущего цикла.
  • Принудительный запуск: runtime.GC().