На платформе Android система пытается использовать как можно больше системной памяти (ОЗУ) и выполняет различные оптимизации памяти, чтобы при необходимости освободить место. Эти оптимизации могут оказать негативное влияние на вашу игру, либо замедлив ее, либо полностью уничтожив. Подробнее об этих оптимизациях можно узнать в теме Распределение памяти между процессами .
На этой странице описаны шаги, которые вы можете предпринять, чтобы избежать проблем с нехваткой памяти, влияющих на вашу игру.
Ответ на onTrimMemory()
Система использует onTrimMemory()
для уведомления вашего приложения о событиях жизненного цикла, которые предоставляют хорошую возможность для вашего приложения добровольно сократить использование памяти и избежать уничтожения убийцей нехватки памяти (LMK), чтобы освободить память для использования другими приложениями.
Если ваше приложение завершается в фоновом режиме, то в следующий раз, когда пользователь запустит ваше приложение, у него произойдет медленный холодный запуск . Приложения, которые уменьшают использование памяти при переходе в фоновый режим, с меньшей вероятностью будут завершаться в фоновом режиме.
При реагировании на события обрезки лучше всего выделять большие объемы памяти, которые не нужны немедленно и могут быть восстановлены по требованию. Например, если в вашем приложении есть кеш растровых изображений, которые были декодированы из локально хранящихся сжатых изображений, то зачастую полезно обрезать или очистить этот кеш в ответ на TRIM_MEMORY_UI_HIDDEN
.
Котлин
class MainActivity : AppCompatActivity(), ComponentCallbacks2 { override fun onTrimMemory(level: Int) { if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Release memory related to UI elements, such as bitmap caches. } if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { // Release memory related to background processing, such as by // closing a database connection. } } }
Ява
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 { public void onTrimMemory(int level) { switch (level) { if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Release memory related to UI elements, such as bitmap caches. } if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { // Release memory related to background processing, such as by // closing a database connection. } } } }
С#
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.
Дополнительные сведения см. в разделе Сбор и чтение отчетов об ошибках .