Расскажите про сборщик мусора (Garbage Collector) в Go.

Ответ

Сборщик мусора (GC) в Go — это ключевой компонент рантайма, отвечающий за автоматическое управление памятью. Он спроектирован с упором на минимизацию задержек (low latency).

Основной алгоритм:

Go использует конкурентный (concurrent) трехцветный алгоритм маркировки и очистки (mark-and-sweep). Это означает, что GC работает параллельно с основной программой, останавливая её лишь на очень короткие промежутки времени (STW - Stop The World).

Этапы работы:

  1. Mark (Пометка): GC ищет достижимые объекты в памяти, начиная с "корней" (глобальные переменные, стеки горутин). Для этого используется трехцветная абстракция:

    • Белые объекты: Потенциальные кандидаты на удаление.
    • Серые объекты: Достижимые, но их дочерние объекты еще не просканированы.
    • Черные объекты: Достижимые, и все их дочерние объекты просканированы.

  2. Sweep (Очистка): После завершения фазы пометки все объекты, оставшиеся белыми, считаются недостижимыми и их память освобождается.


Ключевые особенности GC в Go:

  • Write Barrier (Барьер записи): Специальный механизм, который активируется во время работы GC. Он перехватывает операции записи указателей (например, *p = q) и уведомляет GC, чтобы не потерять достижимые объекты. Это гарантирует, что GC не удалит объект, на который появилась новая ссылка из уже "черного" объекта.
  • Pacer: Алгоритм, который определяет оптимальное время для запуска следующего цикла GC. Он анализирует скорость выделения памяти и стремится завершить сборку мусора к моменту, когда объем кучи удвоится по сравнению с прошлым циклом. Это регулируется переменной GOGC.
  • Минимальные STW-паузы: Большинство фаз GC выполняются конкурентно. Паузы "Stop The World" требуются только для коротких операций, таких как включение/выключение барьера записи и сканирование "корней".
import "runtime"

func main() {
    // Обычно не требуется, но можно принудительно запустить GC
    // для отладки или в специфических сценариях.
    runtime.GC()
}

Начиная с Go 1.18, GC также включает оптимизации, основанные на гипотезе о поколениях, что позволяет эффективнее работать с короткоживущими объектами, хотя это и не является полноценным generational GC, как в Java или .NET.