Можно ли отключить или ограничить запуск сборщика мусора в Go
Что проверяют
Знаете ли вы реальные рычаги управления GC в Go, а не только слово «сборщик». Следом обычно спрашивают про GOMEMLIMIT и о том, как вести себя сервису в контейнере с жёстким лимитом памяти.
Как отвечать
Отключить можно полностью: GOGC=off в окружении или debug.SetGCPercent(-1) из пакета runtime/debug прямо в коде. После этого сборка идёт только при явном runtime.GC() или при подходе к лимиту памяти, если он задан.
Основные рычаги:
GOGC: допустимый рост кучи относительно живых данных после прошлой сборки, по умолчанию 100. При 200 МБ живой кучи следующая сборка начнётся около 400 МБ. Меньшее значение даёт частые сборки и меньше памяти, большее даёт редкие сборки и больше памяти;GOMEMLIMIT(с Go 1.19): мягкий лимит памяти рантайма, в кодеdebug.SetMemoryLimit. Когда процесс к нему подходит, GC работает чаще независимо отGOGC;GOGC=offвместе сGOMEMLIMIT: сборка почти не запускается, пока память далеко от лимита. Подходит для пакетных задач и сервисов с предсказуемым объёмом данных;runtime.GC(): принудительная блокирующая сборка, в продакшен-коде нужна редко.
Затем скажите, что настройка это вторая мера, а первая это меньше аллокаций. Смотреть через GODEBUG=gctrace=1, профиль pprof по alloc_space и go build -gcflags=-m, который показывает, что утекает в кучу. Лечится предвыделением слайсов, sync.Pool для короткоживущих буферов и отказом от лишних указателей.
Уместно упомянуть, что старый трюк с «балластом», большим неиспользуемым массивом для отсрочки сборок, после появления GOMEMLIMIT не нужен.
Где спотыкаются
Говорят, что GC в Go отключить нельзя. Можно, и это одна переменная окружения.
Ставят GOGC=off без лимита. Память растёт до OOM kill, особенно в контейнере.
Выставляют GOMEMLIMIT ровно по лимиту контейнера. Лимит мягкий и учитывает только память рантайма Go, поэтому нужен запас, иначе процесс всё равно убьют. А если живая куча больше лимита, GC крутится почти без остановки, хотя рантайм и ограничивает его долю процессора.