Трешинг GC (мало свободного места в куче) GC thrashing (heap nearly full)
ID причины mem-gc-thrash · Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Серверная инфраструктура
Когда живые данные приближаются к пределу кучи, GC почти нечего освобождать, и сборки идут одна за другой без перерыва.
Почему Из-за роста онлайна на событии или утечки живые данные заполняют кучу почти до предела → Следствие GC освобождает совсем немного, и сразу снова запускается Full GC, большую часть CPU занимает GC → На экране Весь сервер несколько минут то уходит в слоумо, то ловит фризы, а затем падает из-за нехватки памяти
Вечерний пик, При наплыве игроков, Чем дольше без перезапуска
Ответственные
Основной ответственный Команда разработки · Разработка сервера · Совместно Команда инфраструктуры · Серверная инфраструктура
Команда разработки: задачи
Задавать размер кучи с запасом относительно живых данных в пик (обычно как минимум в 2 раза больше), сокращать долгоживущие данные и утечки.
Команда инфраструктуры: задачи
Настроить алерт на долю времени GC, перезапускать сервер сразу, не дожидаясь, что он справится сам, брать инстансы с запасом памяти, чтобы можно было увеличить кучу.
Цифры для ориентира
Если GC занимает больше 10% времени работы, это обычно считают тревожным сигналом. Некоторые сборщики в Java выдают ошибку нехватки памяти, если тратят на GC 98% времени и почти ничего не освобождают.
На графике
Упор в лимит (плато) · куча сразу после GC, доля времени GC
Где смотреть
Смотреть, насколько куча после GC близка к максимальной и какую долю времени занимает GC. Для Java смотреть «после GC(размер кучи)» в строках -Xlog:gc и частоту строк Pause Full, для .NET dotnet-counters (в .NET 8 и ниже % Time in GC since last GC, с .NET 9 прирост dotnet.gc.pause.time), для Go интервалы между строками GODEBUG=gctrace=1
Подтверждает
Даже сразу после GC куча остаётся почти полной, Full GC идут один за другим, доля времени GC сильно выше обычной (как правило, больше 10%). Всё это время тик замедляется на всём сервере
Опровергает
Если после GC в куче есть запас, а паузы всё равно длинные, дело в выборе и настройке сборщика (mem-gc)
Чем проверить
Инструменты инфраструктуры (игровой код не нужен)
Источники
The Parallel CollectorOracle Parallel GC выдаёт OutOfMemoryError, если тратит на GC больше 98% всего времени и освобождает меньше 2% кучи
Garbage-First Garbage Collector TuningOracle По умолчанию (GCTimeRatio=12) G1 подбирает размер кучи так, чтобы GC занимал не больше примерно 8% времени. Full GC из-за слишком заполненной кучи ищут в логе по строкам Pause Full (G1 Compaction Pause)
A Guide to the Go Garbage CollectorGo При GOGC=100 по умолчанию целевой размер кучи примерно в 2 раза больше живой кучи. Если упереться в лимит памяти, GC работает без остановки (трешинг). GODEBUG=gctrace=1 выводит трассировку GC
Garbage Collector ImplementationOracle Строка -Xlog:gc содержит тип GC (Pause Young, Pause Full), «занято до GC->занято после GC(размер кучи)» и длительность паузы