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

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

Высокое потребление памяти может привести к проблемам с поведением приложений и системы, в том числе:

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

Рекомендации по использованию памяти на ТВ-устройствах

Телевизионные устройства обычно имеют значительно меньше памяти, чем телефоны или планшеты. Например, конфигурация, которую мы видим на телевизоре, — это 1 ГБ ОЗУ и разрешение видео 1080p . В то же время большинство телевизионных приложений имеют схожие функции; следовательно, аналогичная реализация и общие проблемы. Эти две ситуации представляют проблемы, не встречающиеся в других типах устройств и приложениях:

  • Приложения Media TV обычно состоят как из изображений с сеткой, так и из полноэкранных фоновых изображений , которые требуют загрузки большого количества изображений в память за короткий период времени.
  • Телевизионные приложения воспроизводят мультимедийные потоки , для которых требуется выделить определенный объем памяти для воспроизведения видео и аудио, а также требуются значительные медиа-буферы для обеспечения плавного воспроизведения.
  • Дополнительные мультимедийные функции (поиск, смена эпизодов, смена звуковой дорожки и т. д.) могут потребовать дополнительной нагрузки на память, если они не реализованы должным образом.

Общие сведения о телевизионных устройствах

В этом руководстве основное внимание уделяется использованию памяти приложений и целевым показателям памяти для устройств с низким объемом оперативной памяти.

При выборе телевизионных устройств учитывайте следующие характеристики:

  • Память устройства : объем оперативной памяти (ОЗУ), установленной в устройстве.
  • Разрешение пользовательского интерфейса устройства : разрешение, которое устройство использует для отображения пользовательского интерфейса ОС и приложений; обычно это ниже разрешения видео устройства.
  • Разрешение видео : максимальное разрешение, с которым устройство может воспроизводить видео.

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

Обзор телевизионных устройств

Память устройства Разрешение видео устройства Разрешение пользовательского интерфейса устройства isLowRAMDevice()
1 ГБ 1080p 720p Да
1,5 ГБ 2160p 1080p Да
≥1,5 ГБ 1080p 720p или 1080p Нет*
≥2 ГБ 2160p 1080p Нет*

ТВ-устройства с малым объемом оперативной памяти

Эти устройства находятся в ситуации с ограниченной памятью и сообщат ActivityManager.isLowRAMDevice() значение true. Приложениям, работающим на ТВ-устройствах с малым объемом оперативной памяти, необходимо реализовать дополнительные меры управления памятью .

Мы считаем, что к этой категории относятся устройства со следующими характеристиками:

  • Устройства с объемом памяти 1 ГБ : 1 ГБ ОЗУ, разрешение пользовательского интерфейса 720p/HD (1280x720), разрешение видео 1080p/FullHD (1920x1080).
  • Устройства 1,5 ГБ : 1,5 ГБ ОЗУ, разрешение пользовательского интерфейса 1080p/FullHD (1920x1080), разрешение видео 2160p/UltraHD/4K (3840x2160)
  • Другие ситуации, в которых OEM-производитель определил флаг ActivityManager.isLowRAMDevice() из-за дополнительных ограничений памяти.

Обычные ТВ-устройства

Эти устройства не страдают от такой значительной нехватки памяти. Мы считаем, что эти устройства имеют следующие характеристики:

  • ≥1,5 ГБ ОЗУ, пользовательский интерфейс 720p или 1080p и разрешение видео 1080p
  • ≥2 ГБ ОЗУ, пользовательский интерфейс 1080p и разрешение видео 1080p или 2160p

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

Цели памяти на ТВ-устройствах с малым объемом оперативной памяти

При измерении памяти на этих устройствах мы настоятельно рекомендуем контролировать каждый раздел памяти с помощью профилировщика памяти Android Studio . Телевизионные приложения должны отслеживать использование памяти и работать над тем, чтобы их категории были ниже пороговых значений, которые мы определяем в этом разделе.

профилировщик памяти

В разделе «Как подсчитывается память» вы найдете подробное объяснение сообщаемых показателей памяти. Для определения порогов для ТВ-приложений мы сосредоточимся на трех категориях памяти:

  • Анонимный + Обмен : состоит из памяти Java + Native + Stack в Android Studio.
  • Графика : сообщается непосредственно в инструменте профилирования. Обычно состоит из графических текстур.
  • Файл : сообщается как категории «Код» + «Другие» в Android Studio.

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

Тип памяти Цель Цели использования (1 ГБ)
Анонимный + обмен (Java + собственный + стек) Используется для выделения памяти, медиабуферов, переменных и других задач, требующих интенсивного использования памяти. < 160 МБ
Графика Используется графическим процессором для текстур и буферов, связанных с отображением. 30-40 МБ
Файл Используется для кодовых страниц и файлов в памяти. 60-80 МБ

Максимальный общий объем памяти (Anon+Swap + Graphics + File) не должен превышать следующее:

  • 280 МБ общего использования памяти ( Anon+Swap + Graphics + File ) для устройств с низким объемом оперативной памяти 1 ГБ.

Настоятельно рекомендуется не превышать:

  • Использование памяти 200 МБ ( Anon+Swap + Graphics ).

Память файлов

В качестве общего руководства по файловой памяти помните, что:

  • В целом файловая память хорошо обрабатывается системой управления памятью ОС.
  • На данный момент мы не обнаружили, что это является основной причиной нехватки памяти.

Однако при работе с файловой памятью в целом:

  • Не включайте в сборку неиспользуемые библиотеки и по возможности используйте небольшие подмножества библиотек, а не полные.
  • Не храните большие файлы открытыми в памяти и освобождайте их, как только закончите с ними.
  • Минимизируйте размер скомпилированного кода для классов Java и Kotlin. См. руководство «Сжатие, запутывание и оптимизация приложения» .

Конкретные рекомендации по телевидению

В этом разделе представлены конкретные рекомендации по оптимизации использования памяти на ТВ-устройствах.

Графическая память

Используйте соответствующие форматы изображений и разрешения.

  • Не загружайте изображения с разрешением, превышающим разрешение пользовательского интерфейса устройства. Например, изображения с разрешением 1080p следует уменьшить до 720p на устройстве с пользовательским интерфейсом 720p.
  • По возможности используйте растровые изображения с аппаратной поддержкой .
    • В таких библиотеках, как Glide, включите функцию Downsampler.ALLOW_HARDWARE_CONFIG , которая по умолчанию отключена. Включение этого параметра позволяет избежать дублирования растровых изображений, которые в противном случае находились бы как в графической, так и в анонимной памяти.
  • Избегайте промежуточных рендерингов и повторных рендерингов.
    • Их можно определить с помощью Android GPU Inspector :
    • Посмотрите в разделе «Текстуры» изображения, которые являются шагами к окончательному рендерингу, а не просто элементами, образующими их. Обычно это так называемый «промежуточный рендеринг».
    • Для приложений Android SDK их часто можно удалить, используя флаг макета forceHasOverlappedRendering:false , чтобы отключить промежуточную визуализацию для этого макета.
    • См. «Избегайте перекрытия рендеров» о перекрывающихся рендерах как отличный ресурс.
  • По возможности избегайте загрузки изображений-заполнителей , используйте @android:color/ или @color для текстур-заполнителей.
  • Избегайте объединения нескольких изображений на устройстве, если композицию можно выполнить в автономном режиме. Предпочитаю загружать отдельные изображения, а не компоновать изображения из загруженных изображений.
  • Следуйте руководству «Обработка растровых изображений» , чтобы лучше работать с растровыми изображениями.

Анон+Подмена памяти

Anon+Swap состоит из выделений Native + Java + Stack в профилировщике памяти Android Studio. Используйте ActivityManager.isLowMemoryDevice() чтобы проверить, ограничено ли устройство памятью, и адаптируйтесь к этой ситуации, следуя этим рекомендациям.

  • СМИ:
    • Укажите переменный размер медиа-буферов в зависимости от оперативной памяти устройства и разрешения воспроизведения видео . Это должно составлять 1 минуту воспроизведения видео:
      1. 40-60 МБ за 1 ГБ/1080p
      2. 60-80 МБ за 1,5 ГБ/1080p
      3. 80-100 МБ за 1,5 ГБ/2160p
      4. 100-120 МБ за 2 ГБ/2160p
    • Свободное распределение памяти мультимедиа при изменении эпизода , чтобы предотвратить увеличение общего объема анонимной памяти.
    • Освобождайте и останавливайте медиа-ресурсы сразу же после остановки приложения: используйте обратные вызовы жизненного цикла активности для обработки аудио- и видеоресурсов. Если вы не являетесь аудиоприложением, остановите воспроизведение , когда onStop() произойдет в ваших действиях, сохраните всю выполняемую вами работу и настройте освобождение ресурсов. Запланировать работу вам может понадобиться позже. См. раздел «Задания и сигналы тревоги» .
    • Обратите внимание на память буфера при поиске видео : разработчики часто выделяют дополнительные 15-60 секунд будущего контента, когда хотят подготовить видео для пользователя, но это создает дополнительные затраты памяти. В общем, не используйте будущий буфер более чем на 5 секунд, пока пользователь не выберет новую позицию видео. Если вам строго необходимо предварительно буферизовать дополнительное время во время поиска, обязательно выполните следующие действия:
      • Заранее выделите буфер поиска и используйте его повторно.
      • Размер буфера должен быть не более 15-25 МБ (в зависимости от памяти устройства).
  • Распределения:
    • Используйте рекомендации по графической памяти , чтобы не дублировать изображения в анонимной памяти.
      • Изображения часто занимают большую часть памяти, поэтому их дублирование может оказать большую нагрузку на устройство. Это особенно актуально при интенсивной навигации по сетке изображений.
    • Освободите выделения, удалив их ссылки при перемещении экранов . Убедитесь, что не осталось ссылок на растровые изображения и объекты.
  • Библиотеки:
    • Профилируйте выделение памяти из библиотек при добавлении новых, поскольку они также могут загружать дополнительные библиотеки, которые также могут выделять память и создавать привязки .
  • Сеть:
    • Не выполняйте блокирующие сетевые вызовы во время запуска приложения , они замедляют время запуска приложения и создают дополнительные затраты памяти при запуске, где память особенно ограничена загрузкой приложения. Сначала покажите загрузочный экран или заставку и выполните сетевые запросы, как только пользовательский интерфейс будет готов.

Привязки

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

Типичные привязки и лучшие практики:

  • API целостности воспроизведения : используется для проверки целостности устройства.
    • Проверьте целостность устройства после экрана загрузки и перед воспроизведением мультимедиа.
    • Перед воспроизведением содержимого освободите ссылки на PlayIntegrity StandardIntegrityManager .
  • Библиотека платежей Play : используется для управления подписками и покупками с помощью Google Play.
    • Инициализируйте библиотеку после экрана загрузки и выполните всю работу по выставлению счетов перед воспроизведением любого мультимедиа.
    • Используйте BillingClient.endConnection() после завершения использования библиотеки и всегда перед воспроизведением видео или мультимедиа.
    • Используйте BillingClient.isReady() и BillingClient.getConnectionState() , чтобы проверить, была ли служба отключена, на случай, если какую-либо работу по выставлению счетов потребуется выполнить снова, а затем снова выполните BillingClient.endConnection() после завершения.
  • Поставщик шрифтов GMS
    • Предпочитайте использовать автономные шрифты на устройствах с низким объемом оперативной памяти, а не использовать поставщика шрифтов, поскольку загрузка шрифтов обходится дорого, и FontsProvider будет связывать службы для этого.
  • Библиотека Google Assistant : иногда используется для поиска и поиска в приложении, если возможно, замените эту библиотеку.
    • Для приложений Leanback : используйте преобразование текста в речь Gboard или библиотеку androidx.leanback .
      • Следуйте рекомендациям по поиску для реализации поиска.
      • Примечание. Функция Leanback устарела , и приложения следует перенести в функцию TV Compose.
    • Для приложений «Создать» :
      • Используйте преобразование текста в речь Gboard для реализации голосового поиска.
    • Внедрите Watch Next, чтобы сделать медиаконтент в вашем приложении доступным для обнаружения.

Службы переднего плана

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

В Android TV и Google TV службам Foreground Services разрешено продолжать работу только после того, как пользователь покинет приложение:

  • Для аудиоприложений : службам переднего плана разрешено продолжать работу только после того, как пользователь покинет приложение, чтобы продолжить воспроизведение звуковой дорожки. Службу необходимо остановить сразу после окончания воспроизведения звука.
  • Для любого другого приложения: все службы переднего плана должны быть остановлены, как только пользователь покинет ваше приложение , поскольку нет уведомления, уведомляющего пользователя о том, что приложение все еще работает и потребляет ресурсы.
  • Для фоновых заданий, таких как обновление рекомендаций или «Смотреть дальше» , используйте WorkManager .

Работы и сигналы тревоги

WorkManager — это современный API-интерфейс Android для планирования повторяющихся фоновых заданий. WorkManager будет использовать новый JobScheduler , если он доступен (SDK 23+), и старый AlarmManager если он отсутствует. Для получения передового опыта выполнения запланированных заданий на телевидении следуйте следующим рекомендациям:

  • Избегайте использования API-интерфейсов AlarmManager в SDK 23+, особенно AlarmManager.set() , AlarmManager.setExact() и подобных методов, поскольку они не позволяют системе определять подходящее время для запуска заданий (например, когда устройство работает на холостом ходу).
  • На устройствах с низким объемом оперативной памяти избегайте запуска заданий без крайней необходимости. При необходимости используйте WorkManager WorkRequest только для обновления рекомендаций после воспроизведения и попытайтесь сделать это, пока приложение еще открыто.
  • Определите Constraints WorkManager, чтобы система могла запускать ваши задания в подходящее время:

Котлин

Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresStorageNotLow(true)
.setRequiresDeviceIdle(true)
.build()

Ява

Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresStorageNotLow(true)
.setRequiresDeviceIdle(true)
.build()
  • Если вам необходимо регулярно запускать задания (например, чтобы обновлять Watch Next на основе активности пользователя по просмотру контента в вашем приложении на другом устройстве), снижайте использование памяти, чтобы потребление памяти заданием не превышало 30 МБ .

Другие общие рекомендации

Следующие рекомендации предоставляют общую информацию о разработке приложений для Android:

  • Минимизируйте выделение объектов, оптимизируйте повторное использование объектов и оперативно освобождайте неиспользуемые объекты.
    • Не храните ссылки на объекты, особенно растровые изображения.
    • Избегайте использования System.gc() и вызовов прямого освобождения памяти, поскольку они мешают процессу обработки памяти в системе. Например, в устройствах, использующих zRAM, принудительный вызов gc() может временно увеличить использование памяти из-за сжатия и распаковки памяти. память.
    • Используйте LazyList например, как показано в браузере каталога в Compose или RecyclerView в уже устаревшем наборе инструментов пользовательского интерфейса Leanback, чтобы повторно использовать представления, а не заново создавать элементы списка.
    • Кэшируйте локально элементы, считываемые от внешних поставщиков контента, которые вряд ли изменятся, и определяют интервалы обновления, которые предотвращают выделение дополнительной внешней памяти.
  • Проверьте возможные утечки памяти.
    • Остерегайтесь типичных случаев утечки памяти , таких как ссылки внутри анонимных потоков, перераспределение видеобуферов, которые никогда не освобождаются, и другие подобные ситуации.
    • Используйте дамп кучи для устранения утечек памяти.
  • Создавайте базовые профили , чтобы минимизировать объем своевременной компиляции, необходимой при запуске приложения при холодном запуске.

Обзор инструментов