На платформе 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()) } }
Будьте консервативны с бюджетами памяти
Рассчитывайте объём памяти разумно, чтобы избежать её исчерпания. Вот некоторые моменты, которые следует учесть:
- Размер физической оперативной памяти : игры часто используют от ¼ до ½ объема физической оперативной памяти устройства.
- Максимальный размер zRAM : чем больше zRAM, тем больше памяти игре потенциально нужно выделить. Этот объём может варьироваться в зависимости от устройства; найдите значение
SwapTotal
в/proc/meminfo
. - Использование памяти ОС : устройства, выделяющие системным процессам больше оперативной памяти, оставляют меньше памяти для игры. Система завершит процесс игры прежде, чем завершит системные процессы.
- Использование памяти установленными приложениями : протестируйте игру на устройствах с большим количеством установленных приложений. Приложения социальных сетей и чатов должны работать постоянно и влияют на объём свободной памяти.
Если вы не можете придерживаться консервативного бюджета памяти, используйте более гибкий подход. Если система сталкивается с проблемами нехватки памяти, уменьшите объём памяти, используемый игрой. Например, выделите текстуры с более низким разрешением или сохраните меньше шейдеров в ответ на onTrimMemory()
. Такой динамический подход к распределению памяти требует от разработчика больше усилий, особенно на этапе разработки игры.
Избегайте избиения
Пробуксовка происходит, когда свободной памяти мало, но недостаточно, чтобы завершить игру. В этой ситуации kswapd
освободил страницы, которые всё ещё нужны игре, поэтому пытается перезагрузить их из памяти. Места недостаточно, поэтому страницы продолжают выгружаться (непрерывный подкачок). Трассировка системы отображает эту ситуацию как поток, в котором kswapd
работает непрерывно.
Одним из признаков подтормаживания является длительное время кадра — возможно, секунду или больше. Чтобы решить эту проблему, уменьшите объём памяти, занимаемый игрой.
Используйте доступные инструменты
В Android имеется набор инструментов, помогающих понять, как система управляет памятью.
Меминфо
Этот инструмент собирает статистику памяти, чтобы показать, сколько памяти PSS было выделено и для каких категорий она использовалась.
Распечатать статистику meminfo можно одним из следующих способов:
- Используйте команду
adb shell dumpsys meminfo package-name
. - Используйте вызов
MemoryInfo
из Android Debug API.
Статистика PrivateDirty
показывает объём оперативной памяти внутри процесса, который не может быть выгружен на диск и не используется другими процессами. Большая часть этого объёма становится доступна системе после завершения процесса.
Точки трассировки памяти
Точки трассировки памяти отслеживают объём памяти RSS , используемой вашей игрой. Расчёт использования памяти RSS выполняется гораздо быстрее, чем расчёт использования памяти PSS. Благодаря более быстрому расчёту RSS обеспечивает более точную детализацию изменений объёма памяти, что позволяет точнее измерять пиковое использование памяти. Таким образом, легче заметить пики, которые могут привести к исчерпанию памяти в игре.
Perfetto и длинные следы
Perfetto — это набор инструментов для сбора информации о производительности и использовании памяти устройства и отображения её в веб-интерфейсе. Perfetto поддерживает трассировки произвольной длины, позволяя отслеживать изменения RSS с течением времени. Вы также можете выполнять SQL-запросы к полученным данным для офлайн-обработки. Включите длинные трассировки в приложении «Трассировка системы» . Убедитесь, что для трассировки включена категория « Память:Память» .
heapprofd
heapprofd
— это инструмент отслеживания памяти, входящий в состав Perfetto. Этот инструмент поможет вам обнаружить утечки памяти, показывая, где память была выделена с помощью malloc
. heapprofd
можно запустить с помощью скрипта Python. Благодаря низким накладным расходам, он не влияет на производительность, как другие инструменты, например, Malloc Debug.
отчет об ошибке
bugreport
— это инструмент для ведения журнала, позволяющий определить, произошла ли ошибка в игре из-за нехватки памяти. Вывод этого инструмента гораздо более подробный, чем у logcat. Он полезен для отладки памяти, поскольку показывает, произошла ли ошибка в игре из-за нехватки памяти или она была завершена LMK.
Более подробную информацию см. в разделе Получение и чтение отчетов об ошибках .