Эффективно управляйте памятью в играх

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

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

Ответ на onTrimMemory()

Система использует onTrimMemory() чтобы уведомить ваше приложение о том, что памяти не хватает и приложение может быть закрыто. Зачастую это единственное предупреждение, которое получает ваше приложение. Этот обратный вызов имеет большую задержку по сравнению с убийцей нехватки памяти (LMK) , поэтому очень важно быстро реагировать на обратный вызов.

В ответ на этот обратный вызов уменьшите скорость, количество и размер выделений. onTrimMemory() передает константу, указывающую серьезность, но вам следует отреагировать на первое предупреждение, поскольку можно выделить быстрее, чем на то, на что может отреагировать onTrimMemory() .

Котлин

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {
    override fun onTrimMemory(level: Int) {
        when (level) {
            ComponentCallbacks2.TRIM_MEMORY_MODERATE,
                ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
                ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> // Respond to low memory condition
            else -> Unit
        }
    }
}

Ява

public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
    public void onTrimMemory(int level) {
        switch (level) {
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
              // Respond to low memory condition
                break;
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
              // Respond to low memory condition
                break;
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
              // Respond to low memory condition
                break;
            default:
                break;

С#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

class LowMemoryTrigger : MonoBehaviour
{
    private void Start()
    {
        Application.lowMemory += OnLowMemory;
    }
    private void OnLowMemory()
    {
        // Respond to low memory condition (e.g., Resources.UnloadUnusedAssets())
    }
}

Используйте бета-версию Memory Advice API

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

Чтобы использовать API Memory Advice, воспользуйтесь руководством по началу работы.

Будьте осторожны с бюджетом памяти

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

  • Размер физической оперативной памяти . Игры часто используют от ¼ до ½ объема физической оперативной памяти устройства.
  • Максимальный размер zRAM : больший размер zRAM означает, что игре потенциально может быть выделено больше памяти. Эта сумма может варьироваться в зависимости от устройства; найдите SwapTotal в /proc/meminfo , чтобы найти это значение.
  • Использование памяти ОС . Устройства, которые выделяют больше оперативной памяти для системных процессов, оставляют меньше памяти для вашей игры. Система убивает процесс вашей игры до того, как она уничтожит системные процессы.
  • Использование памяти установленных приложений . Проверьте свою игру на устройствах, на которых установлено множество приложений. Приложения социальных сетей и чатов должны работать постоянно и влиять на объем свободной памяти.

Если вы не можете придерживаться консервативного бюджета памяти, выберите более гибкий подход. Если в системе возникают проблемы с нехваткой памяти, уменьшите объем памяти, используемой игрой. Например, выделите текстуры с более низким разрешением или сохраните меньше шейдеров в ответ на onTrimMemory() . Такой динамический подход к распределению памяти требует от разработчика дополнительной работы, особенно на этапе дизайна игры.

Избегайте тряски

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

Одним из симптомов тряски является длительное время кадра — возможно, секунда или больше. Чтобы решить эту ситуацию, уменьшите потребление памяти игрой.

Используйте доступные инструменты

В Android имеется набор инструментов, помогающих понять, как система управляет памятью.

Меминфо

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

Распечатайте статистику meminfo одним из следующих способов:

  • Используйте команду adb shell dumpsys meminfo package-name .
  • Используйте вызов MemoryInfo из API отладки Android.

Статистика PrivateDirty показывает объем оперативной памяти внутри процесса, который не может быть выгружен на диск и не используется совместно с другими процессами. Основная часть этого количества становится доступной системе, когда этот процесс завершается.

Точки трассировки памяти

Точки трассировки памяти отслеживают объем RSS-памяти, которую использует ваша игра. Расчет использования памяти RSS происходит намного быстрее, чем расчет использования PSS. Поскольку расчеты выполняются быстрее, RSS показывает более точную детализацию изменений объема памяти для более точных измерений пикового использования памяти. Поэтому легче заметить пики, из-за которых игре может не хватить памяти.

Перфетто и длинные следы

Perfetto — это набор инструментов для сбора информации о производительности и памяти на устройстве и отображения в веб-интерфейсе. Он поддерживает трассировки произвольной длины, поэтому вы можете видеть, как RSS меняется с течением времени. Вы также можете выполнять SQL-запросы к данным, которые он производит, для автономной обработки. Включите длинную трассировку из приложения System Tracing . Убедитесь, что для трассировки включена категория Memory:Memory .

куча

heapprofd — это инструмент отслеживания памяти, входящий в состав Perfetto. Этот инструмент может помочь вам найти утечки памяти, показывая, где память была выделена с помощью malloc . heapprofd можно запустить с помощью сценария Python, и поскольку этот инструмент имеет низкие накладные расходы, он не влияет на производительность, как другие инструменты, такие как Malloc Debug.

отчет об ошибке

bugreport — это инструмент регистрации, позволяющий узнать, произошел ли сбой вашей игры из-за нехватки памяти. Вывод инструмента гораздо более подробный, чем при использовании logcat. Это полезно для отладки памяти, поскольку показывает, произошел ли сбой вашей игры из-за нехватки памяти или она была убита LMK.

Дополнительные сведения см. в разделе Сбор и чтение отчетов об ошибках .