Производительность и профилирование
Профилирование узких мест CPU и GPU в Unreal Engine, оптимизация Tick, Blueprints, анимации, коллизий, UI, вызовов отрисовки, LOD, отсечения по перекрытию, инстансинга и памяти.
22 вопросов
JuniorТеорияОчень частоЧто значит, что кадр упирается в CPU, а что — в GPU?
Что значит, что кадр упирается в CPU, а что — в GPU?
Кадр упирается в CPU, когда дольше всего длится работа процессора (игровая логика, подготовка вызовов отрисовки), и в GPU, когда дольше длится работа видеокарты (шейдинг, пиксели). Более медленная сторона ограничивает частоту кадров, поэтому профилируйте.
Типичные ошибки
- ✗Оптимизировать сторону GPU, когда кадр на деле упирается в CPU
- ✗Считать узкое место фиксированным, а не меняющимся от сцены к сцене
- ✗Угадывать узкое место вместо его измерения профайлером
Уточняющие вопросы
- →Какая консольная команда показывает, во что упирается кадр?
- →Назовите по одной причине CPU-bound и GPU-bound кадра.
JuniorТеорияОчень частоЧто такое LOD (уровень детализации) и почему он важен?
Что такое LOD (уровень детализации) и почему он важен?
LOD — это упрощённая версия меша с меньшим числом треугольников, которая подставляется, когда объект удаляется от камеры. Дальние объекты выглядят почти так же при меньшей геометрии, поэтому LOD снижают нагрузку на GPU без заметной потери качества.
Типичные ошибки
- ✗Думать, что низкие LOD добавляют детали, а не убирают их из меша
- ✗Путать LOD с настройками освещения, теней или качества текстур
- ✗Полностью отключать LOD и рисовать полную геометрию на всех расстояниях
Уточняющие вопросы
- →Что определяет момент переключения движка с одного LOD на другой?
- →Чем HLOD отличается от обычного LOD отдельного меша?
JuniorТеорияОчень частоЧто такое функция Tick и почему она стоит производительности?
Что такое функция Tick и почему она стоит производительности?
Tick — это покадровое обновление, вызываемое у каждого включённого Actor и Component. Его стоимость в том, что движок выполняет вашу логику один раз за кадр, поэтому множество тикающих объектов умножают работу каждый кадр. Отключайте Tick, когда он не нужен.
Типичные ошибки
- ✗Оставлять Tick включённым у Actor, которым нечего делать каждый кадр
- ✗Считать, что Tick идёт с фиксированной частотой, а не зависит от времени кадра
- ✗Класть тяжёлую работу в Tick вместо таймера или события
Уточняющие вопросы
- →Как отключить
Tickу Actor, которому он не нужен? - →Когда таймер лучше, чем тик каждый кадр, и почему?
JuniorТеорияОчень частоКак вы профилируете производительность в Unreal Engine?
Как вы профилируете производительность в Unreal Engine?
Начните с stat unit, чтобы увидеть время кадра, игрового потока, отрисовки и GPU, затем углубитесь через stat game, stat gpu или stat scenerendering. Для детальных трейсов используйте Unreal Insights — он записывает временные шкалы CPU, GPU и памяти.
Типичные ошибки
- ✗Доверять чистому FPS, не разделяя затраты игрового потока, потока рендера и GPU
- ✗Профилировать только в редакторе, игнорируя собранные сборки Development/Shipping
- ✗Думать, что
stat fpsдаёт разбивку по системам — он показывает только частоту
Уточняющие вопросы
- →Что означают четыре числа, которые выводит
stat unit? - →Почему стоит профилировать собранную сборку, а не редактор?
MiddleТеорияЧастоCPU-bound против GPU-bound — как определить, что именно ограничивает кадр?
CPU-bound против GPU-bound — как определить, что именно ограничивает кадр?
Запустите stat unit и сравните: если Game или Draw — наибольшее число, вы CPU-bound; если доминирует GPU, вы GPU-bound. Время кадра примерно равно максимуму из потоков, так как CPU и GPU работают параллельно.
Типичные ошибки
- ✗Считать, что CPU и GPU работают последовательно, и время кадра — их сумма, а не максимум
- ✗Считать любое падение FPS проблемой GPU, игнорируя затраты игрового потока
- ✗Забывать, что
Draw— это затраты CPU (потока рендера), а не GPU
Уточняющие вопросы
- →Что означает, когда
Frameбольше времени любого отдельного потока? - →Как VSync или ограничение частоты кадров искажает диагноз CPU против GPU?
MiddleТеорияЧастоКак найти затратные функции Tick в проекте?
Как найти затратные функции Tick в проекте?
Используйте stat game, чтобы увидеть совокупную стоимость тика, затем снимите трейс в Unreal Insights и изучите временную шкалу игрового потока на события Tick. Строки TickGroup и тайминг по акторам показывают, какие классы доминируют в кадре.
Типичные ошибки
- ✗Считать, что стоимость тика по функциям невидима и измеримо лишь общее время кадра
- ✗Профилировать стоимость
Tickна временной шкале GPU вместо игрового потока - ✗Забывать снять трейс собранной сборки, где число тиков совпадает с релизным
Уточняющие вопросы
- →Как трейс
Unreal Insightsгруппирует тики поTickGroup? - →Почему тик может выглядеть дешёвым на вызов, но всё равно доминировать в кадре?
MiddleТеорияЧастоЧто такое инстансинг и что такое ISM и HISM в Unreal Engine?
Что такое инстансинг и что такое ISM и HISM в Unreal Engine?
Инстансинг отрисовывает много копий одного меша за один вызов отрисовки. ISM (Instanced Static Mesh) хранит эти инстансы; HISM добавляет отсечение по инстансам и автоматический выбор LOD, что подходит для больших открытых россыпей.
Типичные ошибки
- ✗Думать, что каждый инстанс — отдельная копия меша в памяти
- ✗Менять местами роли ISM и HISM — именно у HISM есть отсечение и LOD
- ✗Считать, что инстансинг не сводит вызовы отрисовки воедино
Уточняющие вопросы
- →Почему все инстансы в ISM должны иметь общий набор материалов?
- →Когда Nanite снимает необходимость выбирать между ISM и HISM?
MiddleТеорияЧастоЧто такое LOD и HLOD и чем они различаются?
Что такое LOD и HLOD и чем они различаются?
LOD — это менее детализированная версия одного меша, подменяемая по расстоянию для сокращения треугольников. HLOD объединяет много дальних акторов в один совмещённый прокси-меш, снижая и число треугольников, и число вызовов отрисовки для целых регионов.
Типичные ошибки
- ✗Думать, что LOD добавляет детализацию вблизи, а не убирает её на расстоянии
- ✗Путать LOD (по мешу) с HLOD (много акторов, слитых в один прокси)
- ✗Считать, что HLOD не снижают число вызовов отрисовки
Уточняющие вопросы
- →Когда Nanite делает ручные LOD мешей ненужными?
- →Какие артефакты могут возникнуть на дистанции перехода HLOD?
MiddleКодЧастоРеализуйте пул объектов для снарядов, чтобы избежать затрат на спавн при каждом выстреле
Реализуйте пул объектов для снарядов, чтобы избежать затрат на спавн при каждом выстреле
Заранее создайте фиксированный набор акторов-снарядов один раз, держите их деактивированными и выдавайте свободный при выстреле вместо вызова SpawnActor. Возвращайте отработавшие снаряды в пул деактивацией, а не вызовом Destroy.
Типичные ошибки
- ✗Вызывать
SpawnActor/Destroyвнутри пула, сводя на нет весь его смысл - ✗Оставлять
Tickи коллизию включёнными на простаивающих пулированных акторах - ✗Не сбрасывать состояние снаряда (скорость, урон, владельца) при переиспользовании
Уточняющие вопросы
- →Как обработать опустошение пула при непрерывной стрельбе?
- →Почему возвращённый снаряд должен сбросить скорость и состояние коллизии?
MiddleТеорияЧастоЧто такое отсечение по перекрытию и как Unreal Engine его использует?
Что такое отсечение по перекрытию и как Unreal Engine его использует?
Отсечение по перекрытию пропускает отрисовку объектов, скрытых за другой геометрией. Unreal каждый кадр использует аппаратные occlusion-запросы и тест по иерархическому Z-буферу, поэтому перекрытые меши не выдают вызовов отрисовки, хотя и находятся внутри фрустума.
Типичные ошибки
- ✗Путать отсечение по перекрытию с отсечением по фрустуму
- ✗Думать, что отсечённые объекты уничтожаются, а не просто пропускаются при отрисовке
- ✗Считать, что перекрытие запекается один раз и не работает с динамическими объектами
Уточняющие вопросы
- →Почему occlusion-запросы могут вызывать задержку видимости в один кадр?
- →Когда предвычисленные объёмы видимости предпочтительнее запросов в рантайме?
MiddleТеорияЧастоКак оптимизировать производительность Blueprints в Unreal Engine?
Как оптимизировать производительность Blueprints в Unreal Engine?
Избегайте покадровой работы в Event Tick, предпочитайте события и таймеры, включайте Blueprint Nativization или переносите горячую логику в C++. Кэшируйте ссылки вместо повторных вызовов Get и Cast и убирайте тяжёлые узлы из циклов.
Типичные ошибки
- ✗Считать, что Blueprint работает со скоростью нативного C++ без накладных расходов ВМ
- ✗Вызывать
Castкаждый кадр вместо кэширования приведённой ссылки - ✗Запихивать покадровую логику в
Event Tickвместо использования событий
Уточняющие вопросы
- →Почему узел
Castв плотном цикле — повод для беспокойства о производительности? - →Когда стоит полностью переносить функцию Blueprint в C++?
MiddleТеорияЧастоКак оптимизировать производительность коллизий в Unreal Engine?
Как оптимизировать производительность коллизий в Unreal Engine?
Используйте простые примитивы коллизии вместо потреугольной сложной коллизии, отключайте коллизию на мешах, которым она не нужна, и настраивайте каналы и типы объектов так, чтобы запросы проверяли только релевантные объекты. Избегайте перекрывающихся объёмов запросов.
Типичные ошибки
- ✗Использовать сложную (потреугольную) коллизию там, где хватило бы простого примитива
- ✗Оставлять коллизию включённой на чисто декоративных мешах
- ✗Помещать все объекты на один канал, из-за чего запросы проверяют нерелевантных акторов
Уточняющие вопросы
- →Почему сложная коллизия гораздо дороже бокса или капсулы?
- →Как каналы трассировки снижают стоимость трассировки луча?
MiddleТеорияЧастоКак оптимизировать создание и уничтожение множества акторов в рантайме?
Как оптимизировать создание и уничтожение множества акторов в рантайме?
Используйте пул объектов: создайте акторов заранее один раз и переиспользуйте их, переключая видимость, коллизию и Tick, вместо вызовов SpawnActor/Destroy. Это устраняет аллокации на каждое создание, регистрацию компонентов и нагрузку на сборку мусора.
Типичные ошибки
- ✗Вызывать
SpawnActor/Destroyв плотном цикле и винить сборщик мусора в хитчах - ✗Считать
SpawnActorпотокобезопасным и пригодным для вызова вне игрового потока - ✗Думать, что немедленный
Destroyосвобождает память сразу, а не ставит в очередь GC
Уточняющие вопросы
- →Какое состояние должен сбросить пулированный актор при повторной активации?
- →Как отложенное создание (
SpawnActorDeferred) помогает разбить стоимость спавна?
MiddleТеорияЧастоКак сократить вызовы отрисовки в сцене Unreal Engine?
Как сократить вызовы отрисовки в сцене Unreal Engine?
Объединяйте статические меши, используйте Instanced Static Mesh для повторяющихся ассетов и переиспользуйте материалы, чтобы рендерер мог группировать. Меньше уникальных пар меш-материал и агрессивное отсечение сокращают число вызовов отрисовки потока рендера.
Типичные ошибки
- ✗Считать вызовы отрисовки затратами GPU, а не потока рендера (CPU)
- ✗Давать каждому объекту уникальный материал, ломая группировку
- ✗Думать, что инстансинг увеличивает вызовы отрисовки, а не сводит их в один
Уточняющие вопросы
- →Почему общий материал позволяет двум мешам объединиться в один вызов отрисовки?
- →В чём компромисс между объединёнными мешами и отсечением по мешам?
MiddleТеорияЧастоКак сократить использование Tick в масштабах проекта?
Как сократить использование Tick в масштабах проекта?
Отключите Tick по умолчанию (bCanEverTick = false) и включайте только там, где он нужен. Замените покадровый опрос таймерами, событиями или делегатами и увеличьте TickInterval, чтобы логика, которой не нужен каждый кадр, выполнялась реже.
Типичные ошибки
- ✗Оставлять
bCanEverTickвключённым на акторах без покадровой логики - ✗Опрашивать условие каждый кадр вместо подписки на событие
- ✗Не знать, что
TickIntervalможет замедлить тик, чтобы он выполнялся реже
Уточняющие вопросы
- →Когда таймер подходит лучше, чем замедленный
Tick? - →Чем
bStartWithTickEnabledотличается отbCanEverTick?
MiddleТеорияИногдаКакова цена производительности динамических теней в Unreal Engine?
Какова цена производительности динамических теней в Unreal Engine?
Динамические (movable) источники света каждый кадр перерисовывают сцену в карты глубины теней, умножая геометрические проходы и число вызовов отрисовки. Статические и стационарные источники запекают тени оффлайн, поэтому в рантайме они гораздо дешевле.
Типичные ошибки
- ✗Считать, что movable- и статические источники стоят в рантайме одинаково
- ✗Думать, что динамические тени запекаются, а не перерисовываются каждый кадр
- ✗Игнорировать, что каждый отбрасывающий тень объект добавляет геометрический проход
Уточняющие вопросы
- →Как настройки каскадов теней меняют качество против цены для направленного света?
- →Когда стационарный источник — хороший компромисс между статическим и movable?
MiddleКодИногдаРеализуйте полосу здоровья UMG, которая обновляется без тика каждый кадр
Реализуйте полосу здоровья UMG, которая обновляется без тика каждый кадр
Управляйте полосой через делегат: компонент здоровья транслирует событие OnHealthChanged, а виджет обновляет свой ProgressBar только в этом обработчике. Ни Event Tick, ни покадровая привязка свойства не нужны.
Типичные ошибки
- ✗Использовать привязку свойств UMG, которая молча пересчитывается каждый кадр
- ✗Опрашивать здоровье в
NativeTickвместо реакции на событие изменения - ✗Забыть один раз выставить полосу в текущее значение при создании
Уточняющие вопросы
- →Почему привязка свойства UMG фактически является покадровым
Tick? - →Как гарантировать, что полоса показывает верное значение до первого события?
MiddleТеорияИногдаКак оптимизировать производительность UMG и UI в Unreal Engine?
Как оптимизировать производительность UMG и UI в Unreal Engine?
Замените покадровые привязки свойств обновлениями по событиям, ставьте статичным виджетам SelfHitTestInvisible, отмечайте неизменные поддеревья как Is Volatile = false, чтобы Slate кэшировал их, и используйте Invalidation Box, чтобы пропускать перерисовку стабильного UI.
Типичные ошибки
- ✗Привязывать множество свойств виджетов каждый кадр вместо обновления по событиям
- ✗Оставлять декоративные виджеты
Visibleи реагирующими на ввод вместо невидимых - ✗Думать, что
Invalidation Boxстоит дороже, чем экономит, для стабильного UI
Уточняющие вопросы
- →Как
Invalidation Boxрешает, каких детей перерисовывать? - →Почему привязка свойства дороже явного обновления по событию?
MiddleТеорияИногдаКак профилировать использование памяти в Unreal Engine?
Как профилировать использование памяти в Unreal Engine?
Используйте stat memory и Memreport для снимка, дорожку Memory Insights в Unreal Insights для живых трейсов аллокаций и obj list для разбивки по числу UObject. Профилируйте собранную сборку для реалистичных цифр.
Типичные ошибки
- ✗Думать, что в Unreal нет встроенных средств для памяти и работает лишь профайлер ОС
- ✗Профилировать память только в редакторе, где накладные расходы искажают цифры
- ✗Путать итоги
stat memoryс разбивкой по ассетам или классам
Уточняющие вопросы
- →Что содержит файл
Memreport, чего нет вstat memory? - →Как отследить утечку памяти, которая медленно растёт за много минут?
SeniorТеорияИногдаКак оптимизировать производительность анимации для множества персонажей?
Как оптимизировать производительность анимации для множества персонажей?
Включите URO (Update Rate Optimization), чтобы дальние скелетные меши пересчитывались реже, используйте LOD анимации и переносите тяжёлую логику в Fast Path или в потоковое обновление Animation Blueprint. Отсекайте или замораживайте меши вне экрана.
Типичные ошибки
- ✗Считать, что дальние персонажи стоят столько же, сколько близкие, без URO или LOD
- ✗Полагать, что расчёт костей идёт на GPU, а не на CPU
- ✗Помещать тяжёлую логику в граф событий AnimBP вместо потокового обновления
Уточняющие вопросы
- →Почему логика
Fast Pathв AnimBP должна избегать вызовов функций и узловCast? - →Чем LOD анимации отличается от LOD меша?
SeniorДебаггингРедкоКак отлаживать периодические хитчи кадра в собранной сборке?
Как отлаживать периодические хитчи кадра в собранной сборке?
Снимите трейс Unreal Insights и найдите кадр со всплеском, затем посмотрите, какая дорожка расширилась — игровой поток, GPU, сборка мусора или стриминг ассетов. Стек вызовов всплеска называет виновника; stat unit лишь подтверждает факт хитча. Здесь игровой поток почти весь кадр заблокирован CollectGarbage с ровной периодичностью в десятки секунд — это пауза сборки мусора, а не GPU или стриминг.
Типичные ошибки
- ✗Доверять среднему FPS, который скрывает всплеск в один кадр
- ✗Считать хитчи всегда GPU-bound, игнорируя всплески сборки мусора или стриминга
- ✗Отлаживать только в редакторе, где стриминг и сборка мусора ведут себя иначе
Уточняющие вопросы
- →Как подтвердить, что хитч вызван паузой сборки мусора?
- →Какие настройки снижают хитчи от синхронной загрузки ассетов?
SeniorДебаггингРедкоКак подойти к регрессии в 30 FPS после добавления новой геймплейной системы?
Как подойти к регрессии в 30 FPS после добавления новой геймплейной системы?
Профилируйте до и после через stat unit, чтобы увидеть, какой поток просел, затем снимите трейс Unreal Insights, чтобы найти стоимость новой системы. Делайте бисекцию: отключите систему, чтобы подтвердить причину, прежде чем оптимизировать. Здесь время игрового потока выросло втрое, а draw и GPU не изменились — просел игровой поток; трейс показывает синхронный поиск пути в покадровом Tick каждого агента толпы, умноженный на их число.
Типичные ошибки
- ✗Оптимизировать до замера того, какой поток на самом деле просел
- ✗Пропускать шаг бисекции, подтверждающий, что причина — новая система
- ✗Считать, что геймплейная система стоит только времени игрового потока, но не рендера
Уточняющие вопросы
- →Как отличить регрессию потока рендера от регрессии игрового потока в трейсе?
- →Почему базовый замер до изменения критичен для этого подхода?