← Назад к вопросам

Что происходит в момент запуска сборщика мусора?

1.0 Junior🔥 112 комментариев
#Конкурентность и горутины

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Запуск сборщика мусора в Go: пошаговое описание процесса

Сборщик мусора (Garbage Collector, GC) в Go — это конкурентный, триколорный, маркировочно-очищающий (concurrent, tri-color, mark-sweep) сборщик. Его работа состоит из нескольких фаз, которые выполняются при достижении определенных условий. Рассмотрим, что именно происходит в момент запуска.

Условия и триггеры запуска GC

GC запускается автоматически при выполнении одного из условий:

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

Фазы выполнения сборщика мусора

1. Фаза маркировки (Mark Phase) — Stop-the-World (STW)

В начале маркировки происходит краткая остановка всех горутин (STW — Stop The World):

// Псевдокод, иллюстрирующий начало STW фазы
func gcStart() {
    stopTheWorld() // Все горутины приостанавливаются
    enableWriteBarrier() // Включается барьер записи
    startTheWorld() // Горутины возобновляют работу
}

На этом этапе:

  • Корневые объекты (roots) помечаются как живые (глобальные переменные, локальные переменные в стеке активных горутин, регистры процессора)
  • Включается барьер записи (write barrier) для отслеживания изменений указателей во время конкурентной маркировки

2. Конкурентная маркировка (Concurrent Marking)

Основная работа маркировки происходит параллельно с выполнением программы:

// Упрощенное представление процесса маркировки
func mark() {
    for workQueue.notEmpty() {
        obj := workQueue.pop()
        for _, ptr := range obj.pointers() {
            if !ptr.marked {
                ptr.marked = true
                workQueue.push(ptr)
            }
        }
    }
}

Триколорная алгоритмизация (tri-color abstraction):

  • Черные объекты — обработанные, все их дочерние указатели проверены
  • Серые объекты — обнаруженные, но не обработанные дочерние указатели
  • Белые объекты — еще не обнаруженные (будут удалены)

3. Фаза повторной маркировки (Mark Termination) — STW

Вторая и последняя остановка программы:

  • Завершается оставшаяся маркировка
  • Отключается барьер записи
  • Проверяется полнота маркировки

4. Фаза очистки (Sweep Phase)

Удаление неиспользуемых объектов происходит конкурентно с выполнением программы:

// Принцип работы очистки
func sweep() {
    for span := heap.spans; span != nil; span = span.next {
        for obj in span.objects {
            if !obj.marked {
                free(obj) // Освобождение памяти
            } else {
                obj.marked = false // Сброс маркера для следующего цикла
            }
        }
    }
}

Ключевые оптимизации и особенности

Поколения (Generations) — в Go нет классического разделения на поколения, но используется поколение молодых объектов через выделение в локальных кэшах (mcache).

Pacer (регулятор темпа) — алгоритм, который предсказывает оптимальное время для следующего GC:

// Формула расчета порога следующего запуска
nextGC = liveHeap * (1 + GOGC/100)

Ассоциированные объекты — объекты с финализаторами (finalizer) обрабатываются отдельно и требуют дополнительного цикла сборки.

Влияние на производительность

Паузы GC (GC pauses) — обычно составляют:

  • Фаза 1 (начало маркировки): микросекунды — единицы миллисекунд
  • Фаза 3 (завершение маркировки): обычно менее 100 микросекунд

Потребление CPU — GC использует до 25% ресурсов одного процессорного ядра по умолчанию (настраивается через GOGC).

Настройка и мониторинг

// Пример мониторинга статистики GC
var stats debug.GCStats
debug.ReadGCStats(&stats)
fmt.Printf("Пауз GC: %d, Общее время: %v\n", 
    stats.NumGC, stats.PauseTotal)

Переменные окружения для настройки:

  • GOGC=50 — более частый GC (меньше памяти, больше CPU)
  • GOGC=200 — более редкий GC (больше памяти, меньше CPU)
  • GODEBUG=gctrace=1 — детальная трассировка GC

Проблемы и решения

ПроблемаРешение
Длинные паузы GCУвеличение GOGC, оптимизация структур данных
Высокое потребление CPU GCСнижение аллокаций, пулинг объектов
Утечки памятиИспользование профилировщика (pprof), анализ графа объектов

Сборщик мусора в Go постоянно совершенствуется, и с каждой версией происходят оптимизации. Начиная с Go 1.19, представлен режим мягкого ограничения памяти (soft memory limit), позволяющий лучше контролировать использование памяти в контейнеризованных средах.

Что происходит в момент запуска сборщика мусора? | PrepBro