Как отлаживать периодические хитчи кадра в собранной сборке?
Собранная сборка Development держит 60 FPS, но дёргается каждые ~30-60 секунд. stat unit показывает, что Frame периодически подскакивает с 16 мс до 45 мс. Вы снимаете трейс Unreal Insights (-trace=cpu,gpu,frame,loadtime,memory) и разворачиваете кадр со всплеском на дорожке Frames:
stat unit (кадр со всплеском): Frame 45.2 Game 44.0 Draw 4.1 GPU 9.0
Дорожка Frames на всплеске, ровная частота ~45с:
GameThread 44 мс
└─ CollectGarbage 38 мс (блокирует кадр)
GPU 9 мс
loadtime 0 мс
Определите причину.
Снимите трейс Unreal Insights и найдите кадр со всплеском, затем посмотрите, какая дорожка расширилась — игровой поток, GPU, сборка мусора или стриминг ассетов. Стек вызовов всплеска называет виновника; stat unit лишь подтверждает факт хитча.
- ✗Доверять среднему FPS, который скрывает всплеск в один кадр
- ✗Считать хитчи всегда GPU-bound, игнорируя всплески сборки мусора или стриминга
- ✗Отлаживать только в редакторе, где стриминг и сборка мусора ведут себя иначе
- →Как подтвердить, что хитч вызван паузой сборки мусора?
- →Какие настройки снижают хитчи от синхронной загрузки ассетов?
Сценарий
Собранная сборка Development идёт стабильно на 60 FPS, но раз в несколько секунд кадр «дёргается» — заметный рывок. stat unit показывает, что Frame периодически подскакивает с 16 мс до 45 мс, но какой поток виноват — неясно.
Диагностика
Запустите сборку с трейсингом и откройте трейс в Unreal Insights:
MyGame.exe -trace=cpu,gpu,frame,loadtime,memory
В окне Timing Insights найдите всплеск на дорожке Frames и разверните этот кадр:
- Расширился игровой поток — ищите долгий блок: тяжёлый
Tick, синхронная загрузка или спайк логики. - Видна полоса
CollectGarbage— пауза сборки мусора; кадр заблокирован, пока GC сканирует графUObject. - Расширилась дорожка
GPU— всплеск рендера: тяжёлый эффект, обновление теней. - Виден
loadtime/streaming — синхронная подгрузка ассета или уровня в кадре.
Типичная находка: ровные всплески каждые ~30–60 секунд с полосой CollectGarbage — это сборка мусора.
Исправление
Для хитчей сборки мусора:
- Уменьшите аллокации
UObjectв рантайме — переиспользуйте акторов через пул вместоSpawnActor/Destroy. - Настройте
gc.TimeBetweenPurgingPendingKillObjectsи включите инкрементальную очистку (gc.IncrementalBeginDestroyEnabled), чтобы размазать паузу.
Для синхронной загрузки — переходите на асинхронный стриминг (StreamableManager, Async Load Asset). Для спайков Tick — переносите тяжёлую логику в таймеры или разносите по кадрам.