Профілювання продуктивності мобільної гри
"Гра зависає" — це не діагноз. Зависає тому, що CPU не встигає GPU, тому що GC збирає сміття, тому що текстури не поміщаються в VRAM, тому що шейдер занадто важкий для Adreno 618, або тому що на iOS 17 змінилася поведінка Metal. Без профайлера це здогадування. З ним — конкретні числа та конкретні винуватці.
Інструменти та що кожен показує
Unity Profiler — стартова точка. Режим Deep Profile сповільнює гру, але показує всі виклики з виділенням памяті. Підключається через Development Build + Autoconnect Profiler або USB. Завжди тестуйте на пристрої, не в редакторі: інший GC, інший бекенд рендеринга, інші затримки на пристрої.
Ключові маркери в CPU трейсі:
-
GC.Collect— збір сміття. Якщо > 1 мс і відбувається частіше, ніж раз за кілька секунд — проблема з виділенням у hot path -
Camera.Render→RenderForwardOpaque.Render— основна GPU навантаження -
Physics.Processing— фізика. Якщо > 3 мс при 60 FPS бюджеті — занадто багато колайдерів або неоптимальні налаштування FixedTimestep
Android GPU Inspector (AGI) — для Android на Qualcomm або Mali. Показує GPU час на draw call, pipeline bubbles (паузи між vertex і fragment шейдерами), використання ALU. Критично для розуміння, що саме на GPU важко: геометрія, overdraw або fill rate.
Xcode Instruments — для iOS. Використовуйте Metal System Trace для GPU, Time Profiler для CPU, Allocations для пам'яті. Thermal State в Instruments показує, коли пристрій починає дросселювати через перегрів — частої причини нестабільного FPS після 5 хвилин гри.
Snapdragon Profiler — альтернатива AGI для Adreno. Простіша для snapshot-режиму, добре показує ефективність шейдерів.
Типові знахідки
CPU-bound сцена
Симптом: VSync чекає GPU менше 1 мс (GPU встигає), але кадр все ж займає 20+ мс. CPU — вузьке місце.
Найчастіше винуватець — методи Update() з важкою логікою, LINQ-запити в hot path (кожен створює виділення), або FindObjectsOfType всередину Update (O(n) по всіх об'єктах сцени). Memory Profiler це видно як постійний GC.Alloc кілька КБ кожен кадр.
Розв'язання: перехід на Data-Oriented Technology Stack (DOTS/ECS) для масових об'єктів, або мінімально — кешування результатів, заміна LINQ на явні цикли, event-driven архітектура замість polling.
GPU-bound, Overdraw
Симптом: GPU час високий, але кількість draw call невелика. AGI показує високий Fragment Shader час.
Overdraw — малювання одних і тих же пікселів кілька разів через накладання прозорих об'єктів. У Unity видно в режимі Overdraw у Scene View. Темно-червоні області — малюємо кожен піксель 4+ рази. Типово для 2D-ігор з багатьма рівнями частинок.
Розв'язання: сортування прозорих об'єктів, обмеження одночасно активних частинок, заміна прозорих спрайтів на непрозорі де артистично можливо.
Тепловий дросель
На iPhone після 3–7 хвилин інтенсивної гри температура процесора досягає порогу, і iOS знижує частоту CPU/GPU. FPS падає з 60 до 40–45 без змінених навантажень у грі. Перевіряйте через ProcessInfo.thermalState (iOS) — при .serious або .critical профілактично знижуйте якість графіки.
Android має подібний механізм — PowerManager.getThermalHeadroom() (API 29+).
Формат звіту
Після профілювання виконайте звіт з конкретними маркерами: що зависає, на якому пристрої відтворюється, скільки мс займає, та рекомендацію з пріоритетом. Не "оптимізуйте фізику", а "FixedUpdate в EnemyAI.cs викликає Physics2D.OverlapCircleAll кожні 20 мс при 200 активних ворогах — всього 4.2 мс CPU, переписати на Physics2D.OverlapCircleNonAlloc з пулом результатів".
Терміни: аудит і звіт — два-три робочих дні. Реалізація виправлень — окремий кошторис.







