Оптимизация памяти для игр Unreal Engine на Android.

Использование памяти имеет решающее значение в разработке игр для Android. При разработке игр с использованием Unreal Engine необходимо постоянно анализировать и отслеживать состояние памяти , чтобы соблюдать ограничения по её использованию, предотвращая утечки памяти и чрезмерное выделение памяти.

Экономия памяти за счет сокращения количества перестановок шейдеров.

Удаление неиспользуемых параметров в Lighting или Mobile Shader Permutation Reduction позволяет минимизировать количество перестановок шейдеров. Это значительно уменьшает размер пакета приложения, снижает количество объектов состояния конвейера (PSO) и предотвращает создание неиспользуемых целевых областей рендеринга или фиктивных текстур, что приводит к сокращению памяти во время выполнения и повышению производительности.

Для получения дополнительной информации см. раздел «Различные настройки уменьшения количества перестановок освещения и шейдеров для мобильных устройств» в руководстве по производительности мобильных устройств .

Оптимизация загрузки активов

При загрузке ресурсов с использованием жестких ссылок в память одновременно загружается связанный контент, который даже не используется в игре, что приводит к ненужному потреблению памяти. В частности, при неправильном использовании наследования в Blueprint выделяются ненужные CDO (Class Default Objects) от родительских классов, что приводит к значительной потере памяти. В таких случаях для оптимизации использования памяти следует применять следующие методы.

  • Определение кода C++ и разделение данных : Определение основных функций с использованием UCLASS(Abstract) в коде C++, отделяя их от фактических данных.
  • Минимизация наследования : выполняйте настройку данных и загрузку ресурсов только в базовых узлах Blueprint.
  • Используйте косвенные ссылки : применяйте косвенные ссылки на свойства с помощью TSoftObjectPtr , чтобы избежать жестких ссылок, и асинхронно загружайте ресурсы только тогда, когда это необходимо во время выполнения.
  • Меры предосторожности : При использовании асинхронной загрузки ресурсов убедитесь, что проверки на валидность ( IsValid ) выполняются во время вызова функции обратного вызова по завершении загрузки, чтобы предотвратить появление висячих указателей или сбои.

Для получения дополнительной информации см. разделы «Использование ресурсов» и «Создание мобильных игр с помощью UE5» .

Интеллектуальные указатели и настройка сборки мусора (GC)

Использование интеллектуальных указателей (таких как TSharedPtr и TWeakPtr ) в процессе разработки на C++ предотвращает появление висячих указателей и утечек памяти. Кроме того, использование TWeakPtr позволяет избежать создания сильных ссылок на объекты, поэтому сборщик мусора не увеличивает счетчики ссылок при сборке объектов. Это предотвращает ненужное сохранение объектов и снижает сложность графа ссылок, который должен пройти сборщик мусора, значительно уменьшая накладные расходы на сборку мусора. В мобильных средах сборку мусора можно эффективно управлять, запуская ForceGarbageCollection во время переходов между уровнями или в периоды бездействия, например, когда нет взаимодействия с пользователем. Кроме того, его можно запускать, когда игра находится в видимом состоянии или в фоновом режиме (например, при вызовах onStop ), гарантируя, что сборка мусора будет выполнена без влияния на активный игровой процесс.

Для получения дополнительной информации см. разделы «Сборка мусора» и «Умный указатель» .

Оптимизация с использованием сжатия таблицы перемещений.

Сжатие таблицы перемещений (Relocation Table Compression) — это метод оптимизации, который сжимает размер таблицы перемещений в ELF-бинарных файлах для уменьшения размера бинарных файлов Android . При minSDKVersion Android 23 или выше поддерживается сжатие таблицы перемещений APS; при minSDKVersion 28 или выше дополнительно поддерживается сжатие таблицы перемещений RELR, что значительно уменьшает размер файла .so. Это не только уменьшает размер загружаемого файла, но и снижает объем памяти, занимаемый mmap файла .so во время выполнения, уменьшая общую нагрузку на физическую память.

AndroidToolChain.cs

if (MinSDKVersion >= 28)
{
  Result += " -Wl,--pack-dyn-relocs=android+relr,--use-android-relr-tags";
}
else if (MinSDKVersion >= 23)
{
  Result += " -Wl,--pack-dyn-relocs=android";
}

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

Чтобы проверить, правильно ли применено сжатие RELR к ​​бинарному файлу, используйте инструмент llvm-readelf из Android NDK.

llvm-readelf -d libUnreal.so | grep RELR

На практике сборка шаблона ThirdPerson в Unreal Engine и измерение с помощью dumpsys meminfo подтверждают снижение использования PSS и RSS для .so mmap.

Категория PSS Всего Частный Грязный Частная уборка Swap Dirty RSS Всего
.so mmap Перед сжатием 170,210 24,360 141,564 0 242,204
.so mmap После сжатия 138,031 24,748 108,976 0 210,140

Сжатие текстур

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

Оптимизация потоковой передачи текстур

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