Unity полагается на CPU (с хорошей оптимизацией для SIMD части процессора, напр. SSE на x86 или NEON на ARM) для скиннинга, батчинга, физики, пользовательских скриптов, частиц, и т.д.
GPU используется для шейдеров, вызовов отрисовки, эффектов пост-обработки.
Основная масса проблем (80%) создаётся небольшим количеством ключевых причин (20%). Вы можете использовать профайлер редактора для идентификации наиболее ёмких в использовании CPU вызовов функций и оптимизировать их в первую очередь. Зачастую, оптимизация нескольких ключевых функций может дать существенный прирост общей производительности.
Вам следует удостовериться, что функции вызываются только тогда, когда это действительно нужно. Например, вы можете использовать события, такие как OnBecameVisible и OnBecameInvisible для определения того, что объект не виден, и избежать его обновления. Корутины могут отлично подходить в тех случаях, когда требуется вызвать код, который требует постоянных обновлений, но нет необходимости вызывать его каждый кадр:-
// Do some stuff every frame:
void Update () {
}
//Do some stuff every 0.2 seconds:
IEnumerator SlowUpdate () {
while (true) {
//do something
yield return new WaitForSeconds (0.2f);
}
}
Вы можете использовать класс .NET System.Threading.Thread для запуска тяжёлых вычислений в отдельном потоке. Это позволяет вам выполнять код на нескольких ядрах, но учтите, что API Unity не thread-safe (плохо совместимы с поточностью) - вам следует буферизировать входящие данные и результаты, а также считывать и присваивать их в главном потоке, чтобы иметь возможность использовать вызовы API Unity.
Не весь пользовательский код отображается в профайлере. Но вы можете использовать методы Profiler.BeginSample и Profiler.EndSample, чтобы нужный пользовательский код появился в профайлере.
Профайлер редактора Untiy на данный момент не может отображать GPU данные. Мы работаем с производителями аппаратного обеспечения для того, чтобы это произошло. Tegra устройства должны первыми появиться в профайлере редактора.
PowerVR - отложенный отрисовщик, основанный на тайлах, так что для него невозможно получить время GPU для каждого вызова отрисовки (draw call). Однако, вы можете получить время GPU для всей сцены, используя встроенный профайлер Unity (тот, что выводит результаты в консоль Xcode). Инструменты Apple на данный момент могут лишь сказать как занят GPU и его части, но не выдают время в миллисекундах.
PVRUniSCo выдаёт количество циклов для всего шейдера и примерное количество циклов для каждой строчки в коде шейдера. Windows & Mac! Но он в любом случае не совпадает в точности с тем, что делают драйверы Apple. Всё же, это хорошие примерные измерения.
На Tegra, NVIDIA предоставляет отличные инструменты для замеров производительности, которые делают всё что вы пожелаете - время GPU для каждого вызова отрисовки, количество циклов для шейдеров, форсированную 2x2 текстуру, Null view прямоугольник, работает на Windows, OSX, Linux. PerfHUD ES не работает с потребительскими устройствами просто так, вот потребуется макетная плата (development board) от NVIDIA.
Qualcomm предоставляет отличный профайлер Adreno, который только под Windows, но работает с потребительскими устройствами! Он предоставляет графики временной шкалы, захват кадров, отладку кадров, вызовы API, анализатор шейдеров, “живое” редактирование.
Встроенный профайлер выдаёт хороший обзор для каждого модуля:
Порты, используемые профайлером Unity:
Они должны быть доступны из сетевого узла. То есть, устройства, которые вы пытаетесь профилировать, должны “видеть” эти порты на машине с редактором Unity, в котором запущен профайлер.
Существует память Unity и память mono.
В памяти mono содержатся скриптовые объекты, обёртки для объектов Unity (игровые объекты, ассеты, компоненты и т.д.). Сборщик мусора (Garbage Collector) отрабатывает при недостаточном количестве доступной памяти в момент очередного выделения памяти, или при вызове метода System.GC.Collect().
Память выделяется в блоках кучи. Если в выделенном блоке недостаточно места, может быть выделено больше блоков. Блоки кучи будут храниться в mono до тех пор, пока приложение не закроют. Другими словами, Mono не освобождает любую используемую память для ОС (Unity 3.x). Как только вы выделили некоторое количество памяти, она резервируется для Mono и не доступна для ОС. Даже если вы её освободите, на самом деле она будет доступна только для Mono, а не для ОС. Размер кучи памяти в профайлере будет только увеличиваться и никогда не уменьшится.
Если система больше не может разместить новые данные в выделенном блоке кучи, Mono вызывает “GC” (от Garbage Collector, сборщик мусора) и может выделить новый блок кучи (например, из-за фрагментации).
“Too many heap sections” означает, что вам недостаточно памяти Mono (из-за фрагментации или слишком активного использования).
Используйте System.GC.GetTotalMemory для получения общего количества используемой памяти Mono.
Основной совет - избегайте выделения памяти там, где это возможно.
Память Unity содержит данные ассетов (текстуры, меши, аудио, анимации, и т.д.), игровые объекты, внутренние объекты движка (для отрисовки, частиц, физики, и т.д.). Используйте Profiler.usedHeapSize для получения общего объёма используемой памяти Unity.
Инструментов пока нет, но вы можете использовать описанные ниже варианты.
Вы также можете создать собственный инструмент с помощью вызовов API Unity:-
FindObjectsOfTypeAll (type : Type) : Object[]
FindObjectsOfType (type : Type): Object[]
GetRuntimeMemorySize (o : Object) : int
GetMonoHeapSize
GetMonoUsedSize
UnloadUnusedAssets () : AsyncOperation
System.GC.GetTotalMemory/Profiler.usedHeapSize
Ссылки на загруженные объекты выяснить невозможно. В качестве альтернативы, вы можете использовать “Find references in scene” для публичных переменных.
Иногда игра может упасть с ошибкой “out of memory”, хотя в теории, памяти должно хватать. Когда это происходит, сравните нормальное потребление памяти вашей игры и размер выделенной памяти в момент падения. Если числа не совпадут, значит произошёл скачок в потреблении памяти. Это может произойти по следующим причинам: