Рекомендации по производительности для Unity

Эта статья продолжает статью о рекомендациях по оптимизации производительности для смешанной реальности, но посвящена улучшениям для Unity.

Недавно мы выпустили приложение Quality Fundamentals, которое позволяет решить распространенные проблемы с производительностью, проектированием и средами для приложений HoloLens 2. Это приложение отлично подходит для демонстрации приведенного ниже содержимого.

Самый важный шаг при оптимизации производительности приложений смешанной реальности в Unity — использовать рекомендуемые параметры среды для Unity. В этой статье содержится информация о самых важных конфигурациях сцены для создания производительных приложений смешанной реальности. Некоторые из этих рекомендаций отдельно выделены ниже.

Профилирование с помощью Unity

В Unity доступен встроенный профилировщик Unity , который служит отличным инструментом для сбора ценных сведений о производительности для конкретного приложения. Этот профилировщик можно запустить прямо в редакторе, но метрики не будут отражать условия в реальной среде выполнения, поэтому полученные таким образом результаты следует использовать с осторожностью. Мы рекомендуем выполнять дистанционное профилирование приложения, работающего на реальном устройстве, чтобы получить наиболее точные и применимые результаты.

Для Unity доступна замечательная документация по следующим темам:

  1. Удаленное подключение профилировщика Unity к приложениям UWP
  2. Эффективная диагностика проблем с производительностью с помощью профилировщика Unity

Профилирование GPU

Профилировщик Unity

Подключив профилировщик Unity и добавив профилировщик GPU с помощью действия Add Profiler (Добавить профилировщик) в верхнем правом углу, в средней области профилировщика вы увидите, сколько времени тратится на работу центрального и графического процессоров соответственно. Это позволяет разработчику быстро получить приближенные сведения о требованиях приложения к ЦП или GPU.

Unity CPU vs GPU

Примечание

Чтобы использовать профилирование GPU, необходимо отключить задания графики в параметры проигрывателя Unity. Дополнительные сведения см. в описании модуля профилировщика использования GPU для Unity.

Отладчик фреймов Unity

Еще одним функциональным и ценным инструментом для работы является отладчик фреймов Unity. Он позволяет хорошо понять, что GPU делает в каждым фрейме. Следует обращать внимание на дополнительные целевые объекты отрисовки и команды blit для копирования между ними, так как на HoloLens они очень дороги. В идеале для HoloLens не следует использовать целевые объекты отрисовки вне экрана. Они обычно добавляются при включении дорогостоящих функций отрисовки (например, MSAA, HDR или полноэкранных эффектов, таких как цветение), которые следует избегать.

Наложение частоты кадров HoloLens

На странице System Performance (Производительность системы) портала устройств есть полезная сводка по производительности ЦП и GPU устройства. Здесь можно включить параметры Display frame rate counter in headset (Счетчик частоты кадров отображения в гарнитуре) и Display frame rate graph in headset (График частоты кадров отображения в гарнитуре). Эти параметры активируют счетчик и график частоты кадров соответственно, что позволяет моментально оценить работу любого запущенного на устройстве приложения.

PIX

Для профилирования приложений Unity также можно использовать PIX. Кроме того, доступны подробные инструкции по использованию и установке PIX для HoloLens 2. В сборке разработки области, которые отображаются в отладчике фреймов Unity, также доступны в PIX для более подробного просмотра и профилирования.

Примечание

Unity предоставляет возможность легко изменять разрешение цели отрисовки в приложении при выполнении с помощью свойства XRSettings.renderViewportScale. Итоговое изображение на устройстве имеет фиксированное разрешение. Платформа выполняет выборку из выходных данных самого низкого разрешения, чтобы создать изображение с более высоким разрешением для отображения на экране.

UnityEngine.XR.XRSettings.renderViewportScale = 0.7f;

Рекомендации по производительности ЦП

Ниже приводятся более подробные рекомендации по производительности, которые особенно касаются разработки на C# в Unity.

Кэширование ссылок

Мы рекомендуем кэшировать ссылки на все важные компоненты и игровые объекты во время инициализации, так как повтор вызовов функций, например GetComponent<T>() и Camera.main, требует больше ресурсов памяти чем хранение указателя. . Camera.main фактически использует FindGameObjectsWithTag() для выполнения ресурсоемкого поиска объекта камеры в графе сцены по тегу MainCamera.

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    private Camera cam;
    private CustomComponent comp;

    void Start() 
    {
        cam = Camera.main;
        comp = GetComponent<CustomComponent>();
    }

    void Update()
    {
        // Good
        this.transform.position = cam.transform.position + cam.transform.forward * 10.0f;

        // Bad
        this.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 10.0f;

        // Good
        comp.DoSomethingAwesome();

        // Bad
        GetComponent<CustomComponent>().DoSomethingAwesome();
    }
}

Примечание

Отказ от использования GetComponent(string)
При использовании GetComponent() существует несколько разных перегрузок. Важно всегда использовать реализации на основе конкретных типов, но не перегрузку поиска на основе строк. Поиск по строке в сцене значительно дороже, чем поиск по типу.
(Хорошо) Component GetComponent(Type type)
(Хорошо) T GetComponent<T>()
(Плохо) Component GetComponent(string)>

Отказ от дорогостоящих операций

  1. Отказ от использования LINQ

    Хотя запросы LINQ могут быть очень понятыми и простыми для чтения и записи, обычно они требуют больше ресурсов для вычислений и хранения по сравнению с использованием написанных вручную алгоритмов.

    // Example Code
    using System.Linq;
    
    List<int> data = new List<int>();
    data.Any(x => x > 10);
    
    var result = from x in data
                 where x > 10
                 select x;
    
  2. Распространенные API Unity

    Некоторые API Unity при всей очевидной пользе могут быть достаточно ресурсоемкими. Большинство из них выполняют поиск соответствующих игровых объектов по всему графу сцены. Обычно этих операций можно избежать, кэшируя ссылки или создав компонент управления игровыми объектами для отслеживания ссылок во время выполнения.

        GameObject.SendMessage()
        GameObject.BroadcastMessage()
        UnityEngine.Object.Find()
        UnityEngine.Object.FindWithTag()
        UnityEngine.Object.FindObjectOfType()
        UnityEngine.Object.FindObjectsOfType()
        UnityEngine.Object.FindGameObjectsWithTag()
        UnityEngine.Object.FindGameObjectsWithTag()
    

Примечание

Удалите все SendMessage() и BroadcastMessage() любой ценой. Эти функции работают на три порядка медленнее, чем прямые вызовы функций.

  1. Остерегайтесь упаковки-преобразования

    Концепция упаковки-преобразования очень важна в языке и среде выполнения C#. Так называют процесс создания переменных со ссылочным типом в виде оболочек для переменных со значениями типа, такими как char, int, bool и т. д. Если переменная со значением типа "упакована", она помещается в объект System.Object, который хранится в управляемой куче. Для нее выделяется память и ее нужно обрабатывать сборщиком мусора после освобождения. Такие процессы выделения и освобождения ресурсов приводят к снижению производительности, а во многих случаях их можно убрать или легко заменить на менее дорогостоящую альтернативу.

    Чтобы избежать упаковки, убедитесь, что переменные, поля и свойства, в которых хранятся числовые типы и структуры (включая Nullable<T>), строго типизированы как конкретные типы, такие как int, float? или MyStruct, вместо использования объекта. Если эти объекты помещаются в список, обязательно используйте строго типизированный список, например List<int>, а не List<object> или ArrayList.

    Пример упаковки-преобразования в C#

    // boolean value type is boxed into object boxedMyVar on the heap
    bool myVar = true;
    object boxedMyVar = myVar;
    

Повторяющиеся пути кода

Нужно уделять особое внимание всем повторяющимся функциям обратного вызова Unity (т. е. обновления), которые выполняются много раз за секунду и (или) кадр. Любые дорогостоящие операции в этом коде будут иметь огромное и стабильное влияние на производительность.

  1. Пустые функции обратного вызова

    Несмотря на внешнюю безобидность приведенного ниже кода приложения, эти пустые обратные вызовы могут быть очень ресурсоемкими, особенно учитывая, что каждый скрипт Unity выполняет автоматическую инициализацию с помощью метода Update. Unity придется постоянно переключаться между неуправляемой и управляемой частью кода, то есть между кодом UnityEngine и кодом приложения. Такое переключение контекста на этой границе требует много ресурсов, даже если не выполняется никаких действий. Это особенно проблематично, если приложение использует сотни игровых объектов, компоненты которых имеют повторяющиеся пустые обратные вызовы Unity.

    void Update()
    {
    }
    

Примечание

Update() служит самым ярким примером этой проблемы с производительностью, но некоторые другие повторяющиеся обратные вызовы Unity могут оказаться не менее или даже более серьезными, как например следующие: FixedUpdate(), LateUpdate(), OnPostRender(), OnPreRender(), OnRenderImage() и т. п.

  1. Однократное выполнение операций для каждого кадра

    Следующие API Unity содержат операции, типичные для многих голографических приложений. Хотя и не всегда, результаты таких функций часто можно вычислять один раз за кадр и повторно использовать в приложении для всего этого кадра.

    а) Мы рекомендуем выделить один отдельный класс или службу, чтобы обработать Raycast для взгляда на сцену и повторно использовать полученный результат во всех остальных компонентах сцены, не повторяя идентичные операции Raycast для каждого компонента. В некоторых приложениях нужно выполнять Raycast из разных позиций или с разными LayerMask.

        UnityEngine.Physics.Raycast()
        UnityEngine.Physics.RaycastAll()
    

    б) Избегайте операций с методом GetComponent() в повторяющихся обратных вызовах Unity, таких как Update(), используя кэширование ссылок в Start () или Awake().

        UnityEngine.Object.GetComponent()
    

    в) Мы рекомендуем по возможности создавать экземпляры всех объектов при инициализации и применять пулы объектов для повторного использования игровых объектов в ходе работы приложения.

        UnityEngine.Object.Instantiate()
    
  2. Отказ от использования интерфейсов и виртуальных конструкций

    Вызов функций через интерфейсы вместо прямого обращения к объектам либо вызов виртуальных функций часто будут гораздо более ресурсоемкими, чем использование прямых конструкций или прямых вызовов функций. Если виртуальная функция или интерфейс являются необязательными, их следует удалить. Однако для этих подходов ухудшение производительности будет хорошим компромиссом, если их применение упрощает совместную разработку, повышает удобочитаемость или удобство поддержки кода.

    В общем случае мы не рекомендуем объявлять поля и функции виртуальными, если нет четкого понимания, что этот элемент придется перезаписывать. Разработчикам нужно быть особенно осторожными в путях кода с высокой частотой исполнения, то есть вызываемых один и более раз для каждого кадра, таких как метод UpdateUI().

  3. Отказ от передачи структур по значению

    В отличие от классов, для структуры типы определяются значением, и при прямой передаче в функцию их содержимое копируется в только что созданный экземпляр. Эта копия повышает нагрузку на ЦП и требует дополнительной памяти из стека. Нагрузка небольших структур на ресурсы обычно минимальна и может считаться приемлемой. Но для тех функций, которые несколько раз вызываются для каждого кадра и (или) принимают крупные структуры, по возможности измените определение функции так, чтобы передавать им ссылку. Дополнительные сведения см. здесь

Прочее

  1. Физика

    а) Как правило, для улучшения обработки физики следует ограничить количество времени или количество итераций в секунду, затрачиваемых на ее обработку. Это снизит точность имитации. См. документацию по TimeManager в Unity.

    б) Типы коллайдеров в Unity могут иметь очень разные характеристики производительности. В приведенном ниже списке коллайдеры перечислены в порядке уменьшения производительности, слева направо. Важнее всего избегать коллайдеров сетки, которые значительно требовательнее к ресурсам, чем коллайдеры примитивов.

    Сфера < Капсула < Коробка <<< Сетка (выпуклая) < Сетка (невыпуклая)

    Дополнительные сведения см. в статье с рекомендациями по обработке физики в Unity.

  2. Анимации

    Избавьтесь от анимации простоя, отключив компонент Animator (отключение объекта Game не дает такого эффекта). Избегайте шаблонов разработки, в которых аниматор в цикле постоянно присваивает значение одному параметру. Такой метод создает значительную нагрузку на ресурсы без видимого эффекта в приложении. Дополнительные сведения доступны здесь.

  3. Сложные алгоритмы

    Если приложение использует сложные алгоритмы, такие как обратная кинематика, поиск пути и т. д., попробуйте найти более простой подход или оптимизируйте соответствующие параметры по производительности.

Рекомендации по производительности взаимодействия ЦП с GPU

Как правило, производительность взаимодействия ЦП с GPU упирается в вызовы отрисовки, передаваемые на графическую плату. Чтобы повысить эту производительность, вызовы отрисовки следует стратегически уменьшать и (или) реструктуризовать до достижения оптимальных результатов. Поскольку вызовы отрисовки сами по себе требуют много ресурсов, снижение их количества позволит сократить общий объем работы. Кроме того, изменения состояния между вызовами отрисовки требуют ресурсоемких операций по проверке и преобразованию в графическом драйвере, а значит реструктуризация вызовов отрисовки в приложении для ограничения изменений состояния (т. е. разных материалов и т. д.) может повысить производительность.

В документации по Unity есть отличная статья с обзорным и подробным описанием пакетной обработки вызовов на этой платформе.

Однопроходная отрисовка экземпляра

Однопроходная отрисовка экземпляра в Unity позволяет уменьшить число вызовов отрисовки для каждого глаза до одного экземпляра. Благодаря согласованности кэша между двумя вызовами отрисовки будет заметно и некоторое улучшение производительности GPU.

Включение этой функции в проекте Unity

  1. Откройте Player XR Settings (Параметры XR проигрывателя), выбрав элементы Edit>Project Settings>Player>XR Settings (Редактирование > Параметры проекта > Проигрыватель > Параметры XR)
  2. Выберите Single Pass Instanced (Однопроходный с экземпляром) в раскрывающемся меню Stereo Rendering Method (Метод стереоскопической отрисовки), установив также флажок Virtual Reality Supported (Поддержка виртуальной реальности)

Ознакомьтесь со следующими статьями Unity, чтобы получить подробные сведения об этом подходе к отрисовке.

Примечание

Одна из распространенных проблем при однопроходной отрисовке с использованием экземпляра возникает в тех случаях, если уже существующие пользовательские шейдеры не поддерживают создание экземпляра. После включения этой возможности разработчики заметят, что некоторые игровые объекты отрисовываются только для одного глаза. Это связано с тем, что соответствующие пользовательские шейдеры не имеют нужных свойств для создания экземпляров.

Действия для решения этой проблемы описаны в документе Unity об однопроходной стереоскопической отрисовке для HoloLens.

Пакетная обработка статических объектов

Unity поддерживает создание пакетов из нескольких статических объектов, что позволяет снизить число вызовов отрисовки для GPU. Пакетная обработка статических объектов будет нормально работать в Unity для большинства объектов Renderer, которые имеют одинаковый материал и имеют атрибут Static (чтобы присвоить его, выберите объект в Unity и щелкните флажок в верхней правой части окна инспектора). Игровые объекты, имеющие атрибут Static, не могут перемещаться на протяжении всего периода работы приложения. Это означает, что пакетную обработку статических объектов трудно применить для HoloLens, поскольку здесь почти каждый объект должен быть перемещаемым, масштабируемым и т. д. Для иммерсивных гарнитур пакетная обработка статических объектов позволяет значительно сократить число вызовов отрисовки, а значит и повысить производительность.

Дополнительные сведения см. в разделе о пакетной обработке статических объектов в статье Пакетная обработка вызовов отрисовки в Unity.

Пакетная обработка динамических объектов

Поскольку при разработке для HoloLens будет затруднительно объявлять объекты статическими, компенсировать этот недостаток можно применением пакетной обработки динамических объектов. Это будет работать и для иммерсивных гарнитур. Однако пакетная обработка динамических объектов в Unity может быть сложной, поскольку игровые объекты должны иметь одинаковые материалы и соответствовать множеству других критериев.

Полный список этих требований см. в разделе о пакетной обработке динамических объектов в статье Пакетная обработка вызовов отрисовки в Unity. Чаще всего игровые объекты не удается объединить в пакет, поскольку для такой обработки данные о сетке не могут содержать более 300 вершин.

Другие методики

Пакетная обработка возможна только в том случае, если несколько игровых объектов имеют один и тот же материал. Обычно это невозможно из-за того, что для каждого игрового объекта нужна уникальная текстура соответствующего материала. Существует метод создания текстурного атласа, при котором несколько текстур объединяются в одну большую текстуру.

Более того, во всех случаях, где это возможно и оправдано, лучше объединять несколько сеток в один игровой объект. Каждый отрисовщик в Unity будет использовать собственные вызовы отрисовки, и этого можно избежать при одном отрисовщике для объединенной сетки.

Примечание

Изменение свойств в Renderer.material во время выполнения приводит к созданию копии материала, что может нарушить возможность пакетной обработки. Используйте Renderer.sharedMaterial для изменения свойств общего материала для нескольких игровых объектов.

Рекомендации по производительности GPU

Дополнительные сведения об оптимизации отрисовки графических объектов в Unity см. здесь.

Пропуская способность и скорость заливки

При отрисовке кадра на GPU возможности приложения ограничены пропускной способностью памяти или скоростью заливки.

  • Пропускная способность памяти — это скорость операций чтения и записи из памяти, которую может обеспечить GPU.
    • В Unity измените параметр Texture Quality (Качество текстур) в меню Edit>Project Settings>Quality Settings (Правка — Параметры проекта — Параметры качества).
  • Скорость заливки — это число пикселей, которое может отрисовывать GPU в секунду.

Оптимизация совместного использования буфера глубины

Мы рекомендуем включить параметр Depth buffer sharing (Совместное использование буфера глубины) в разделе Player XR Settings (Параметры проигрывателя смешанной реальности) для повышения стабильности голограммы. Но если вы включаете повторное проецирование на поздней стадии на основе глубины с этим параметром, мы рекомендуем выбрать 16-разрядный формат глубины, а не 24-разрядный. 16-разрядные буферы глубины существенно снизят нагрузку на пропускную способность (передачу данных) для буфера глубины, а значит и энергопотребление. Это позволит одновременно снизить энергопотребление и повысить производительность. Но использование 16-разрядного формата глубины может иметь два неприятных последствия.

Z-конфликт

Снижение четкости по глубине при 16-разрядном буфере повышает вероятность Z-конфликтов по сравнению с 24-разрядными буферами. Чтобы избежать таких артефактов, измените ближнюю и дальнюю отсекающие плоскости для камеры Unity с учетом снижения разрешения. Для приложений на основе HoloLens дальняя плоскость обрезки в 50 м вместо стандартного для Unity значения 1000 м обычно полностью устраняет Z-конфликты.

Отключение буфера трафаретов

Если Unity создает текстуру отрисовки с 16-разрядной глубиной, буфер трафаретов не создается. Согласно документации по Unity, выбор 24-разрядного формата глубины приводит к созданию 24-разрядного z-буфера и 8-разрядного буфера трафаретов (https://docs.unity3d.com/Manual/SL-Stencil.html) (если на устройстве применим 32-разрядный формат, что обычно справедливо для устройств HoloLens).

Отказ от полноэкранных эффектов

Некоторые техники для полного экрана могут быть ресурсоемкими из-за того, что их работа в каждом кадре исчисляется миллионами операций. Мы рекомендуем отказаться от эффектов постобработки, таких как сглаживание, свечение и т. п.

Оптимальные параметры освещения

Глобальное освещение в реальном времени в Unity дает потрясающие визуальные результаты, но требует довольно ресурсоемких вычислений. Мы рекомендуем отключать глобальное освещение в реальном времени для всех сцен Unity. Для этого нужно в разделе Window>Rendering>Lighting Settings> (Окно > Отрисовка > Параметры освещения) снять флажок Real-time Global Illumination (Глобальное освещение в реальном времени).

Более того, мы рекомендуем отключить все тени, так как они требуют дополнительных ресурсов GPU для сцены Unity. Тени можно отключать отдельно для каждого источника света или глобально через параметры качества.

Выберите Edit>Project Settings (Редактировать > Свойства проекта), затем категорию Quality> (Качество) и укажите вариант Low Quality (Низкое качество) для платформы UWP. Можно также отдельно указать для свойства Shadows (Тени) значение Disable Shadows (Отключить тени).

С моделями в Unity рекомендуется использовать просчитанное освещение (baked lighting).

Уменьшение количества многоугольников

Количество полигонов можно снизить следующими способами:

  1. Удаление объектов из сцены.
  2. Прореживание ресурсов, которое позволяет снизить количество полигонов для некоторой сетки.
  3. Внедрение в приложение системы уровня детализации, которая отрисовывает более далекие объекты с меньшим числом полигонов без изменения их геометрии.

Общие сведения о шейдерах в Unity

Для сравнения производительности шейдеров можно использовать упрощенную оценку среднего числа операций, выполняемых каждым из них в среде выполнения. В Unity это выполнить очень легко.

  1. Выберите нужный ресурс шейдера или материал, затем в верхнем правом углу окна Inspector (Инспектор) выберите значок шестеренки и действие Select Shader (Выбрать шейдер).

    Select shader in Unity

  2. После выбора ресурса шейдера нажмите кнопку Compile and show code (Компилировать и показать код) в окне Inspector (Инспектор).

    Compile Shader Code in Unity

  3. После компиляции найдите раздел статистики в области результатов, где отображается число разных операций для вершинных и пиксельных шейдеров (учтите, что пиксельные шейдеры часто называют фрагментными).

    Unity Standard Shader Operations

Оптимизация пиксельных шейдеров

Изучая результаты статистики, полученные описанным выше методом, вы можете заметить, что фрагментный шейдер в среднем выполняет больше операций, чем вершинный шейдер. Фрагментный шейдер, также именуемый пиксельным шейдером, выполняется отдельно для каждого пикселя на экране, а вершинный шейдер выполняется только для вершин всех сеток, отрисовываемых на экране.

Таким образом, фрагментные шейдеры не только выполняют больше операций, чем вершинные (из-за сложных вычислений освещения) но и почти всегда применяются к более крупному набору данных. Например, при размере экрана 2000 на 2000 пикселей фрагментный шейдер будет выполнен 2000 × 2000 = 4 000 000 раз. При отрисовке для двух глаз это число удваивается, так как работают сразу два экрана. Если приложение смешанной реальности использует несколько проходов, полноэкранные эффекты постобработки или отрисовку нескольких сеток в пределах одного пикселя, это количество еще значительно увеличится.

Таким образом, снижение числа операций во фрагментных шейдерах обычно значительно больше влияет на производительность, чем аналогичная оптимизация в вершинном шейдере.

Альтернативы стандартному шейдеру Unity

Вместо отрисовки на основе физических параметров или другого шейдера высокого качества, попробуйте применить более производительный и более дешевый шейдер. В наборе средств для смешанной реальности предоставляется стандартный шейдер MRTK, который оптимизирован для проектов смешанной реальности.

В Unity также доступны упрощенные версии шейдеров (без освещенности, с освещенностью вершин, диффузное освещение и т. д.), которые работают быстрее стандартного шейдера Unity. Дополнительные сведения см. в статье об использовании и производительности встроенных шейдеров.

Предварительная загрузка шейдера

Предварительная загрузка шейдера и некоторые другие приемы позволяют оптимизировать время загрузки шейдера. В частности, предварительная загрузка шейдера позволяет избежать задержек, связанных с компиляцией шейдера во время выполнения.

Ограничение перерисовки

В Unity можно отобразить перерисовку сцены, переключившись на меню режима отрисовки в верхнем левом углу представления сцены и выбрав параметр Overdraw (Перерисовка).

Обычно перерисовка устраняется отбрасыванием объектов до того, как они будут отправлены в GPU. Unity предоставляет подробные сведения о реализации отбрасывания загораживаемых объектов для этой платформы.

Рекомендации по использованию памяти

Операции выделения и освобождения памяти в больших объемах могут значительно снижать производительность голографического приложения, что приведет к нестабильному поведению, зависанию кадров и другим неприятным эффектам. При разработке в Unity особенно важно понимать особенности использования памяти, так как управление памятью здесь реализовано через сборщик мусора.

Сборка мусора

Голографические приложения тратят вычислительное время процессора на сбор мусора, когда он активируется для анализа объектов, вышедших из поля зрения в процессе выполнения и требующих удаления из памяти, чтобы использовать ее повторно. Постоянные операции выделения и освобождения памяти обычно требуют более частого вызова сборщика мусора, что ухудшает производительность и взаимодействие с пользователем.

Unity предоставляет отличный ресурс, на котором подробно описана работа сборщика мусора и собраны рекомендации по повышению эффективности работы с памятью в коде.

При разработке в Unity одной из самых распространенных ошибок, которые приводят к избыточному сбору мусора, является отсутствие кэша для ссылок на компоненты и классы. Все ссылки следует собирать в методе Start() или Awake() и использовать повторно в функциях Update() и LateUpdate().

Еще немного советов.

  • Используйте класс C# StringBuilder для динамического создания сложных строк в процессе выполнения.
  • Удалите все вызовы Debug.Log(), когда в них отпадет необходимость, иначе они будут по-прежнему выполняться в рабочих версиях приложения.
  • Если голографическое приложение часто требует большого объема памяти, попробуйте вызывать System.GC.Collect() на этапах загрузки, например при отображении экрана загрузки или перехода между сценами.

Использование пулов объектов

Использование пулов объектов — это распространенный метод для снижения затрат на постоянное выделение или освобождение памяти для объектов. Для этого выделяется большой пул идентичных объектов, из которого извлекаются для повторного использования доступные и неактивные экземпляры. Это эффективнее, чем постоянный процесс создания и уничтожения объектов. Пулы объектов отлично подходят для многократно используемых компонентов с переменными периодами жизни в приложении.

Производительность при запуске

Мы рекомендуем начать работу приложения с небольшой сцены, а затем загружать остальную часть с помощью SceneManager.LoadSceneAsync . Это позволит приложению максимально быстро перейти к интерактивному состоянию. При активации новой сцены создается пиковая нагрузка на ЦП, что может привести к подвисанию или отрывистому отображению содержимого. Для обхода этой проблемы можно установить для параметра загружаемой сцены AsyncOperation.allowSceneActivation значение False, затем дождаться полной загрузки сцены, очистить экран и вернуть этому параметру значение True для завершения активации сцены.

Не забывайте, что в процессе загрузки сцены пользователю будет отображаться голографический стартовый экран.

См. также статью