Пока освобождается использованная и уже ненужная память (мусор), вся игра стоит. Характерный признак: микрофризы через равные промежутки.
Почему Каждый кадр создаются и выбрасываются временные строки, массивы и списки → Следствие Когда мусора накапливается много, GC останавливает главный поток и освобождает память → На экране Регулярные микрофризы раз в несколько секунд или десятков секунд
Основной ответственный Команда разработки · Разработка клиента
Команда разработки: задачи
Сократить аллокации (избегать конкатенации строк, LINQ, захвата переменных в лямбдах), использовать пулы объектов, держать включённым инкрементальный GC (по умолчанию с Unity 2020), запускать GC заранее, когда пауза не мешает, например на экране загрузки.
Цифры для ориентира
Обычно от единиц ms до 100 ms за раз, на слабых телефонах и в играх, которые расходуют много памяти, дольше (в эксперименте около 150–170 ms). GC в Unity при каждом запуске проверяет всю кучу, поэтому чем больше памяти занимает игра, тем дольше пауза.
На графике
Всплески с постоянным периодом · время кадра, моменты запуска GC
Где смотреть
В development-сборке смотреть маркеры GC.Collect и GC.Alloc в профайлере Unity. В Unreal смотреть stat GC и stat Hitches (пишет в лог кадры дольше порога t.HitchFrameTimeThreshold)
Подтверждает
В каждом долгом кадре есть участок GC.Collect примерно той же длины, что и всплеск, а всплески повторяются через равные промежутки от нескольких секунд до десятков секунд. В людных местах растёт GC.Alloc на кадр
Опровергает
Если в долгих кадрах нет участка GC, это «Синхронная загрузка и компиляция шейдеров в главном потоке» или «Нагрузка на рендеринг при большом скоплении игроков»
Чем проверить
Нужны логи и метрики игрового сервера или клиента
Подробнее
Типично для клиентов на C#, например на Unity. Главный виновник: код, который каждый кадр заново создаёт строки боевого лога, цифры урона и тексты UI. Если микрофризы бывают только в людных местах, значит, где-то есть код, который создаёт тем больше мусора, чем больше вокруг игроков. Инкрементальный GC собирает мусор понемногу в каждом кадре (в Unity по умолчанию 3 ms), но если мусор появляется быстрее, чем собирается, в итоге всё равно случается одна большая пауза. В Unreal Engine тоже есть собственный GC, который убирает неиспользуемые игровые объекты. С настройками по умолчанию он запускается примерно раз в минуту (зависит от версии движка и настроек) и может давать рывок раз в минуту. В клиентах, где игровая логика написана на скриптовом языке вроде Lua, отдельно работает ещё и GC этого языка.
Источники
Garbage collection modesUnity Инкрементальный GC включён по умолчанию и собирает мусор частями за несколько кадров. Если его выключить, главный поток стоит всё время проверки кучи, вплоть до сотен ms
Profiler markers referenceUnity GC.Collect: время, пока код программы стоит из-за сборки мусора (от менее 1 ms до сотен ms), GC.Alloc: аллокация в управляемой куче
Stat Commands in Unreal EngineEpic Games stat GC (статистика сборки мусора), stat Hitches (пишет в лог кадры дольше t.HitchFrameTimeThreshold)