GOGC и GOMEMLIMIT
«Полка» переехала в контейнер с лимитом памяти 512 МБ и в первую же ночь словила OOM-kill. Сергей поставил задачу: настроить память так, чтобы под перестал убивать сервис.
GOGC — ручка обмена памяти на CPU: он задаёт целевой размер кучи (heap goal); GOMEMLIMIT — мягкий лимит памяти, чтобы жить в контейнере, но от OOM сам по себе не защищает.
GOGC
Основная ручка настройки — переменная окружения GOGC. По умолчанию GOGC=100, и это процент, задающий целевой размер кучи — heap goal: примерно живое + (живое + корни GC) × GOGC/100, корни учитываются с Go 1.18. Запускает сборку пейсер раньше цели: если после сборки живо 100 МБ, следующая начнётся где-то на пути к 200 МБ, а не ровно на 200.
GOGC=200— сборки вдвое реже, куча растёт вдвое больше.GOGC=50— сборки вдвое чаще, куча меньше.GOGC=off— отключает сборку по порогу роста: куча будет расти, пока не упрётся в лимит. Без лимита это путь к OOM.
Это прямой обмен памяти на процессор: чаще собирать — меньше памяти, но больше CPU на сборку; реже — наоборот.
GOMEMLIMIT
С Go 1.19 есть GOMEMLIMIT — мягкий лимит на память, которой распоряжается сам рантайм. Появился как ответ на контейнеры: у пода в Kubernetes жёсткий лимит памяти, и процесс, который о нём не знает, рискует быть убитым по OOM.
Мягкость — сразу в двух местах. Лимит считает кучу Go вместе со стеками горутин и служебными структурами рантайма, но не внешнюю память: сам бинарник, память cgo и всё, что ОС держит вне контроля Go. А ещё лимит — цель, а не стена: куча может превышать его не только коротким всплеском. При большом живом наборе или когда GC ограничен по CPU (рантайм отводит сборке примерно половину CPU-времени) превышение держится подолгу, а слишком низкий лимит даёт thrashing. Поэтому GOMEMLIMIT от OOM не защищает.
Типовая настройка
Когда куча приближается к GOMEMLIMIT, GC начинает собирать чаще, даже если GOGC говорит «ещё рано». При GOGC=off и заданном лимите сборки всё равно будут, чтобы держаться в нём. Типичная настройка для сервиса в контейнере: оставить GOGC по умолчанию или поднять его, а GOMEMLIMIT поставить чуть ниже лимита пода, оставив запас под cgo и всё, что в лимит не входит.
Вы узнаете:
- как
debug.SetMemoryLimitзадаёт лимит из кода - почему GOMEMLIMIT не заменяет лимит пода
Проверьте себя
Что делает GOGC=200 по сравнению с GOGC=100?
Защищает ли GOMEMLIMIT от OOM kill?
Что произойдёт при GOGC=off без GOMEMLIMIT?
правильных ответов
GOGC задаёт целевой размер кучи — память против CPU; GOMEMLIMIT — мягкий лимит под контейнер, который от OOM не спасает. Пара «GOGC побольше + GOMEMLIMIT с запасом» — стандарт для подов.
10 000 ₽ · 60 минут · онлайн