Что происходит в программе при отсутствии доступной памяти
Что проверяют
Понимаете ли вы, что нехватка памяти в Go это не ошибка, которую можно обработать, а завершение процесса. Интервьюер хочет услышать про поведение рантайма, ОС и контейнера. Следом обычно спрашивают, как вы найдёте причину роста памяти и как ограничить потребление.
Как отвечать
Разделите сценарии:
- рантайм не получил память: Go завершает программу с
fatal error: runtime: out of memory. Это не паника:recoverеё не перехватывает, отложенныеdeferне выполняются.makeиnewникогда не возвращаютnilпри нехватке памяти; - OOM killer: на Linux с overcommit выделение виртуальной памяти обычно проходит, а когда кончается физическая, ядро убивает процесс сигналом
SIGKILL. В контейнере это код выхода 137 и статусOOMKilledв Kubernetes. Процесс не успевает ни записать лог, ни корректно завершиться; - некорректный размер:
make([]byte, n)с отрицательной длиной даёт обычную паникуmakeslice: len out of range. Её перехватить можно, но к нехватке памяти она отношения не имеет; - переполнение стека: бесконечная рекурсия упирается в лимит стека горутины (около 1 ГБ на 64-битных системах) и тоже заканчивается фатальной ошибкой.
Как защищаться. С Go 1.19 есть мягкий лимит GOMEMLIMIT (или debug.SetMemoryLimit): при приближении к нему сборщик мусора запускается чаще. Его ставят чуть ниже лимита контейнера, но если живых данных больше лимита, процесс всё равно упадёт. Причину ищут через pprof: профиль heap показывает, кто держит память, профиль goroutine показывает зависшие горутины. Метрики снимают через runtime/metrics. Частые источники: горутины, навсегда заблокированные на канале, маленький срез, удерживающий большой массив, кеш без ограничения размера.
Где спотыкаются
Говорят, что make вернёт nil или что нехватку памяти можно поймать через recover. Оба утверждения неверны.
Путают утечку памяти с утечкой горутин. В Go вторая встречается чаще: каждая зависшая горутина держит свой стек и всё, на что ссылается.
Считают, что сборщик мусора сам всё решит. Он освобождает только недостижимые объекты, а объект в глобальной мапе достижим всегда.