Ответ
Сборщик мусора (GC) в Go — это ключевой компонент рантайма, отвечающий за автоматическое управление памятью. Он спроектирован с упором на минимизацию задержек (low latency).
Основной алгоритм:
Go использует конкурентный (concurrent) трехцветный алгоритм маркировки и очистки (mark-and-sweep). Это означает, что GC работает параллельно с основной программой, останавливая её лишь на очень короткие промежутки времени (STW - Stop The World).
Этапы работы:
Mark (Пометка): GC ищет достижимые объекты в памяти, начиная с "корней" (глобальные переменные, стеки горутин). Для этого используется трехцветная абстракция:
- Белые объекты: Потенциальные кандидаты на удаление.
- Серые объекты: Достижимые, но их дочерние объекты еще не просканированы.
- Черные объекты: Достижимые, и все их дочерние объекты просканированы.
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.