Как работает garbage collector в Go
Что проверяют
Знаете ли вы, что сборщик в Go конкурентный и не перемещает объекты, и умеете ли связать это с эксплуатацией: почему память не возвращается операционной системе сразу и чем крутить GOGC и GOMEMLIMIT.
Как отвечать
- Алгоритм: конкурентный трёхцветный mark and sweep. Поколений нет, уплотнения нет, объекты не переезжают: указатели стабильны, cgo и unsafe работают, а с фрагментацией борются классы размеров.
- Паузы stop the world есть, но короткие и не зависят от размера кучи: две паузы порядка десятков микросекунд на включение и выключение барьера записи. Маркировка идёт параллельно с горутинами, а гибридный барьер записи (с Go 1.8) ловит указатели, которые меняются по ходу.
- Механизм GC assist: горутина, которая аллоцирует быстрее, чем идёт маркировка, обязана сама пометить часть объектов. Отсюда ощущение, что тормозит именно ваш код, а не сборщик.
- Sweep ленивый: освобождённая память возвращается в кучу процесса, а системе её отдаёт фоновый scavenger, с задержкой.
- Настройки:
GOGCпо умолчанию 100 задаёт целевой размер кучи как живой набор, умноженный на (1 + GOGC/100), то есть сборка при удвоении живой памяти.GOGC=offвыключает сборку,GOMEMLIMIT(Go 1.19) ставит мягкий предел памяти и это правильный инструмент для контейнера с лимитом. В Go 1.25 появился экспериментальный алгоритм маркировки Green Tea. - Снижают нагрузку не вызовом
runtime.GC(), а сокращением аллокаций: escape-анализ черезgo build -gcflags=-m, преаллокация слайсов,sync.Pool, меньше указателей в структурах.
Где спотыкаются
Описывают сборщик по аналогии с JVM: поколения, выжившие, уплотнение кучи. Ничего этого в Go нет.
Утверждают, что пауз не бывает вовсе. Они есть, просто короткие и почти не растут вместе с кучей.
Читают GOGC=200 как «сборка при росте на 200 процентов от старта». Это множитель к живому набору после прошлой сборки: цель становится тройным его размером.
Судят об утечке по RSS процесса. Освобождённые страницы отдаются системе не сразу, реальную картину показывают runtime.ReadMemStats и профиль heap в pprof.