Оптимизация использования оперативной памяти в играх

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

От иммерсивных приложений до игровых миров и 3D-сцен

Наша выделенная команда для VR/AR/MR-разработки, Unity-продакшна и 3D-моделирования и анимации с собственными кейсами и презентациями.

Посетить персонализированный сайт
Показано 1 из 1 услугВсе 242 услуг
Оптимизация использования оперативной памяти в играх
Сложная
от 2 рабочих дней до 2 недель
Часто задаваемые вопросы
Наши компетенции
Какие этапы разработки игры?
Последние работы
  • image_games_mortal_motors_495_0.webp
    Разработка игры для компании Mortal Motors
    683
  • image_games_a_turnbased_strategy_game_set_in_a_fantasy_setting_with_fire_and_sword_603_0.webp
    Пошаговая стратегия в фэнтези сеттинге With Fire And Sword
    860
  • image_games_second_team_604_0.webp
    Разработка игры для компании Second term
    490
  • image_games_phoenix_ii_606_0.webp
    3D-анимация — тизер для игры phoenix 2.
    533

Оптимизация использования оперативной памяти в играх

Краш без предупреждения на устройствах с 3 ГБ RAM — это не случайность. Это результат накопленного memory pressure, который iOS и Android тихо копят, пока не убивают процесс. SIGKILL приходит без лога, без стека, без объяснений. И разработчики часто списывают это на «нестабильность движка», хотя реальная причина — неуправляемый рост heap в Mono/IL2CPP и несвоевременная выгрузка ассетов.

Проблема в том, что Unity Memory Profiler часто показывает «всё нормально» — 400 МБ, казалось бы, некритично. Но native-память, которую удерживают Texture2D объекты без явных ссылок, там не видна. Нужен Total System Memory из Profiler window, а не только Managed Heap.

Три источника утечек, которые мы находим в каждом втором проекте

Незакрытые AssetBundle-ссылки. Разработчик загрузил AssetBundle, достал из него спрайт, но не вызвал bundle.Unload(false). Спрайт в памяти. Потом спрайт уничтожен, но нативный объект Texture2D всё ещё удерживается через WeakReference в ResourceManager. Через 10 загрузок/выгрузок локаций — память не возвращается. Классическая фрагментация Unity native heap. Решение: переход на Addressables с явным управлением временем жизни через AsyncOperationHandle.Release().

Дублирование текстур при смене сцен. При переходе между сценами через SceneManager.LoadScene с параметром LoadSceneMode.Single старая сцена выгружается, но если в новой сцене есть текстуры с теми же именами, загруженные через Resources.Load в коде — они могут оказаться в памяти дважды до вызова Resources.UnloadUnusedAssets(). На проектах с тяжёлыми сценами (100+ МБ текстур) это приводит к пику потребления памяти в момент перехода — именно тогда происходят крэши.

AudioClip с неправильными настройками Load Type. AudioClip с Load Type = Decompress On Load распаковывает PCM в память при загрузке и держит там. Для длинной музыкальной темы это может быть 50–80 МБ только для одного клипа. Правило: музыка → Streaming, короткие SFX → Compressed In Memory, критичные SFX с минимальной задержкой → Decompress On Load только если длина < 2 секунд.

Как работаем с памятью

Memory Profiler (com.unity.memoryprofiler) — основной инструмент. Делаем snapshot в нескольких точках игрового сессии: после старта, после загрузки первой сцены, в середине геймплея, после смены сцены. Сравниваем через Compare Snapshots. Ищем объекты, которые растут от снимка к снимку и не должны.

Особое внимание — Texture2D в списке Objects. Сортируем по Memory Size, открываем References для подозрительных объектов — смотрим, кто их держит.

Addressables как архитектурное решение. Переход с Resources на Addressables даёт явный контроль над временем жизни ассетов. AssetReference + LoadAssetAsync + Release — полный цикл без «магии». Настраиваем профили памяти через Addressables Analyze: Check Duplicate Bundle Dependencies находит ассеты, упакованные в несколько бандлов одновременно (типичная причина дублирования в памяти).

Из практики: мобильный экшен, 9 уровней. После прохождения 3 уровней подряд — краш на iPhone 8. Memory Profiler показал 847 МБ при старте 4 уровня. Источник — 12 уникальных UI-атласов, загруженных через Resources.Load в Lobby-сцене, не выгружались между уровнями. После переноса на Addressables с явным Release при входе в игровую сцену и Resources.UnloadUnusedAssets в coroutine — пик снизился до 480 МБ.

Пул объектов вместо Instantiate/Destroy. Каждый Instantiate выделяет новую память, каждый Destroy не возвращает её мгновенно — GC Alloc накапливается. Object Pool через Unity ObjectPool<T> (встроен с 2021 LTS) полностью устраняет эту категорию аллокаций для снарядов, врагов, VFX.

Этапы работы

  1. Снятие baseline-метрик через Profiler на целевом устройстве (не Editor)
  2. Серия Memory Profiler snapshots по игровому циклу
  3. Анализ топ-10 объектов по потреблению памяти
  4. Выявление источников утечек через Compare Snapshots
  5. Приоритизация по impact: текстуры → AudioClip → Managed Heap → пулинг
  6. Реализация исправлений с промежуточными замерами
  7. Нагрузочное тестирование: 1 час игровой сессии без рестарта
Масштаб задачи Ориентировочные сроки
Аудит памяти + отчёт 2–4 дня
Устранение 2–3 конкретных источников утечек 1–2 недели
Переход Resources → Addressables + оптимизация 3–6 недель
Полная архитектурная переработка управления ассетами 6–12 недель

Стоимость — после аудита текущего состояния проекта.