На этой странице объясняется, как заблаговременно сократить использование памяти в вашем приложении. Информацию о том, как операционная система Android управляет памятью, см. в разделе «Обзор управления памятью» .
Оперативная память (RAM) — ценный ресурс для любой среды разработки программного обеспечения, и она ещё более ценна для мобильной операционной системы, где физическая память часто ограничена. Хотя и среда выполнения Android (ART), и виртуальная машина Dalvik выполняют стандартную сборку мусора, это не означает, что можно игнорировать, когда и где ваше приложение выделяет и освобождает память. Вам всё ещё необходимо избегать утечек памяти — обычно вызванных сохранением ссылок на объекты в статических переменных-членах — и освобождать любые объекты Reference в соответствующее время, определяемое функциями обратного вызова жизненного цикла.
Сократите объем кода и потребляемых ресурсов вашего приложения.
Некоторые ресурсы и библиотеки в вашем коде могут потреблять память, даже если вы этого не замечаете. Общий размер вашего приложения, включая сторонние библиотеки или встроенные ресурсы, может влиять на объем потребляемой им памяти. Вы можете улучшить потребление памяти вашим приложением, удалив из кода избыточные, ненужные или громоздкие компоненты, ресурсы и библиотеки.
Уменьшите общий размер приложения, включив R8.
Скомпилированный код вашего приложения является активной частью памяти, используемой во время выполнения. Каждый класс, метод, зависимость от библиотеки и строковая константа должны быть загружены в оперативную память при запуске. Чем больше ваш скомпилированный код, тем больше физической оперативной памяти требуется вашему приложению для работы.
Вы можете использовать R8 для уменьшения объема памяти, используемой вашим приложением . Хотя R8 традиционно известен уменьшением размера APK , он оказывает прямое положительное влияние на память во время выполнения (RAM). R8 анализирует байт-код вашего приложения, чтобы удалить неиспользуемый код, объединить избыточные классы и встроенные методы, а также минимизировать идентификаторы. Загрузка меньшего количества скомпилированного байт-кода из APK в ОЗУ уменьшает общий базовый объем памяти, используемый приложением. Кроме того, минимизация имен классов, методов и полей в более короткие идентификаторы напрямую снижает накладные расходы на ОЗУ. Оптимизации, такие как слияние классов и обширное встраивание методов, также заменяют дорогостоящие операции поиска и выделения памяти во время выполнения, что приводит к оптимизации памяти в куче и стеке.
Поймите правила хранения
Правила сохранения — это инструкции конфигурации, которые указывают R8, какие части вашего кода следует сохранять во время оптимизации, предотвращая удаление или минификацию кода, от которого зависит ваше приложение. Для получения дополнительной информации см. раздел «О правилах сохранения» .
Неправильно сформулированные правила сохранения (keep rules) мешают R8 оптимизировать значительные части вашего кода. Избегайте слишком общих правил сохранения и следуйте этим рекомендациям:
- Глобальные правила, которых следует избегать:
-
-dontoptimize: Полностью отключает оптимизацию для всего приложения, что приводит к увеличению размера и замедлению работы исполняемых файлов. -
-dontshrink: Предотвращает удаление неиспользуемого кода и ресурсов. -
-dontobfuscate: Предотвращает минификацию имен, что приводит к потере ценной экономии памяти (особенно в больших приложениях).
-
Избегайте использования символов подстановки, применяемых ко всему пакету: общие правила, такие как
-keep class com.example.package.** { *; }, заставляют R8 сохранять каждый класс, поле и метод в этом пакете. Это полностью исключает возможность R8 удалять, оптимизировать или минимизировать код в этом пакете.Используйте стандартный конфигурационный файл R8: всегда используйте
proguard-android-optimize.txt.
Более подробную информацию о написании правил сохранения см. в разделе «О правилах сохранения» . Конкретные шаблоны, которые следует использовать и которых следует избегать, см. в разделе «Рекомендации по использованию правил сохранения» .
Анализатор конфигурации R8 предоставляет информацию о вашей конфигурации R8 и о том, как каждое правило сохранения влияет на ваше приложение. Для получения дополнительной информации о том, как определить правила, блокирующие оптимизацию, см. раздел «Использование анализатора конфигурации R8» .
Будьте осторожны при использовании сторонних библиотек.
Код внешних библиотек часто не предназначен для мобильных устройств и может быть неэффективным при работе с мобильными клиентами. При использовании внешней библиотеки может потребоваться её оптимизация для мобильных устройств. Заранее спланируйте эту работу и проанализируйте библиотеку с точки зрения размера кода и объёма используемой оперативной памяти, прежде чем использовать её.
Даже некоторые библиотеки, оптимизированные для мобильных устройств, могут вызывать проблемы из-за различий в реализации. Например, одна библиотека может использовать облегченные протобуфы, а другая — микропротобуфы, что приведет к двум разным реализациям протобуфов в вашем приложении. Это может произойти с различными реализациями логирования, аналитики, фреймворков для загрузки изображений, кэширования и многих других вещей.
Хотя оптимизация вашего приложения с помощью R8 может удалить неиспользуемый код из зависимостей, её эффективность часто ограничена внутренней конфигурацией библиотеки. Например, общие правила сохранения или использование рефлексии внутри библиотеки могут помешать R8 уменьшить размер кода, что приведет к увеличению потребления памяти. Для получения рекомендаций по выбору эффективных библиотек см. раздел «Выбирайте библиотеки с умом» .
Избегайте использования разделяемых библиотек только для одной или двух функций из десятков. Не добавляйте большой объем кода и накладных расходов, которые вам не нужны. Принимая решение об использовании библиотеки, ищите реализацию, которая максимально соответствует вашим потребностям. В противном случае, вы можете решить создать собственную реализацию.
Используйте Hilt для внедрения зависимостей.
Фреймворки внедрения зависимостей могут упростить написание кода и предоставить адаптивную среду, полезную для тестирования и других изменений конфигурации.
Если вы планируете использовать фреймворк внедрения зависимостей в своем приложении, рассмотрите возможность использования Hilt — рекомендуемой библиотеки внедрения зависимостей для Android, работающей поверх Dagger. Hilt не использует рефлексию для сканирования кода вашего приложения. Вы можете использовать статическую реализацию Hilt на этапе компиляции в приложениях Android без ненужных затрат во время выполнения или использования памяти.
Другие фреймворки внедрения зависимостей, использующие рефлексию, инициализируют процессы, сканируя ваш код на наличие аннотаций. Этот процесс может потребовать значительно больше циклов ЦП и оперативной памяти и вызвать заметное замедление при запуске приложения.
При использовании внедрения зависимостей следует избегать утечек памяти, обеспечивая правильную область видимости объектов. Хранение объектов дольше, чем необходимо, путем привязки их к неправильному жизненному циклу может привести к утечкам памяти.
Подходите к загрузке изображений осознанно.
Графические растровые изображения обычно являются самыми большими распространенными объектами, хранящимися в памяти вашего приложения. Даже если вы работаете со сжатыми файлами, такими как JPEG, файл необходимо преобразовать в несжатое растровое изображение для отображения на экране. Небольшой сжатый файл изображения может превратиться в очень большое растровое изображение.
Например, большинство растровых изображений используют конфигурацию ARGB_8888 , что означает, что каждому пикселю требуется 4 байта памяти — по одному байту для красного, зеленого, синего и альфа-канала (прозрачности). Если у вас есть JPEG-файл размером 100 КБ, и вы отображаете его в окне 1000×1000 пикселей, то для каждого из этих 1 000 000 пикселей потребуется 4 байта, что в сумме составит 4 МБ памяти.
Существует несколько способов оптимизировать использование изображений. Например, использование библиотек для загрузки изображений может помочь освободить память, когда она не нужна. Информацию об эффективной обработке изображений см. в разделе «Оптимизация растровых изображений» .
Отслеживание доступной памяти и её использования.
Прежде чем исправлять проблемы с использованием памяти вашим приложением, необходимо их обнаружить. Профилировщик памяти Android Studio помогает находить и диагностировать проблемы с памятью следующими способами:
- Узнайте, как ваше приложение распределяет память с течением времени. Профилировщик памяти отображает график в реальном времени, показывающий, сколько памяти использует ваше приложение, количество выделенных объектов Java и когда происходит сборка мусора.
- Запустите сборку мусора и сделайте снимок кучи Java во время работы вашего приложения.
- Запишите данные о выделении памяти вашим приложением , проверьте все выделенные объекты, просмотрите трассировку стека для каждого выделения и перейдите к соответствующему коду в редакторе Android Studio.
Профилировщик памяти также интегрирован с библиотекой обнаружения утечек LeakCanary . Используя LeakCanary, вы можете перенести анализ утечек памяти с тестового устройства на свою машину для разработки, что может значительно ускорить рабочий процесс. Для получения дополнительной информации см. примечания к выпуску Android Studio .
Существуют и другие инструменты, которые можно использовать для диагностики проблем с памятью на основе данных от пользователей, запускающих ваше рабочее приложение:
- Используйте Android Vitals для отслеживания событий, связанных с нехваткой памяти.
- Используйте
ProfilingManagerдля отслеживания ошибок нехватки памяти, а также аномального поведения приложения, которое может быть вызвано утечками памяти.
Освобождение памяти в ответ на события
Android может освободить память для вашего приложения или полностью остановить его при необходимости, чтобы освободить память для критически важных задач, как описано в разделе «Обзор управления памятью» . Для дальнейшего балансирования системной памяти и предотвращения необходимости остановки процесса вашего приложения системой, вы можете реализовать интерфейс ComponentCallbacks2 в классах Activity . Предоставленный метод обратного вызова onTrimMemory уведомляет ваше приложение о событиях жизненного цикла или связанных с памятью событиях, которые предоставляют хорошую возможность для вашего приложения добровольно сократить использование памяти. Освобождение памяти может уменьшить частоту принудительного завершения работы вашего приложения из -за нехватки памяти .
В вашей реализации onTrimMemory сосредоточьтесь исключительно на событиях TRIM_MEMORY_UI_HIDDEN и TRIM_MEMORY_BACKGROUND . (Начиная с Android 14, система больше не отправляет уведомления для других устаревших констант. Эти константы были официально объявлены устаревшими в Android 15.)
TRIM_MEMORY_UI_HIDDEN: Этот сигнал указывает на то, что пользовательский интерфейс вашего приложения вышел из поля зрения пользователя. Этот переход предоставляет возможность освободить значительные объемы памяти, непосредственно связанные с пользовательским интерфейсом, такие как растровые изображения, буферы воспроизведения видео или сложные ресурсы анимации.TRIM_MEMORY_BACKGROUND: Этот сигнал указывает на то, что ваш процесс находится в фоновом режиме и теперь может быть завершен для удовлетворения потребностей системы в глобальной памяти. Чтобы продлить время, в течение которого ваш процесс остается в кэшированном состоянии, и уменьшить количество холодных перезапусков приложения, следует активно освобождать любые ресурсы, которые можно легко восстановить после возобновления пользователем своей сессии.
В этом примере кода показано, как реализовать функцию обратного вызова onTrimMemory в составном компоненте для реагирования на различные события, связанные с памятью:
import android.content.ComponentCallbacks2
// Other import statements.
class MainActivity : AppCompatActivity(), ComponentCallbacks2 {
// Other activity code.
/**
* Release memory when the UI becomes hidden or when system resources become low.
* @param level the memory-related event that is raised.
*/
override fun onTrimMemory(level: Int) {
// The app's UI is no longer visible to the user.
if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
// Release memory related to UI elements.
// Example: Clear image loading libraries' memory caches,
// release video player buffers, or drop large custom view bitmaps.
}
// The app is in the background and the system is running low on memory.
if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
// Release memory related to background processing, such as by
// closing a database connection or dropping network caches.
}
}
}
Событие TRIM_MEMORY_UI_HIDDEN указывает на то, что пользовательский интерфейс вашего приложения больше не виден пользователю. Поскольку интерфейс скрыт, вы можете освободить большие ресурсы, связанные с интерфейсом, которые можно легко восстановить, когда пользователь вернется в ваше приложение. Размещение этой логики в Activity или Fragment (а не в ViewModel ) гарантирует, что вы случайно не допустите утечки Context .
В таких случаях следует сосредоточиться на устранении тяжелых визуальных элементов:
- Кэширование растровых изображений: Изображения потребляют большой объем памяти. Если вы используете стороннюю библиотеку для загрузки изображений (например, Coil, Glide или Picasso), вызовите ее специальные функции
clearMemory. - Буферы мультимедиа: Если ваш пользовательский интерфейс включает воспроизведение видео или аудио (например, ExoPlayer), отпустите плеер или очистите его буферы мультимедиа.
- Пользовательские кэши представлений: Если у вас есть компоненты пользовательского интерфейса с высокой степенью кастомизации, которые предварительно отрисовывают или кэшируют объекты
BitmapилиCanvasдля сложных анимаций, обнулите эти кэши.
Проверьте, сколько памяти вам нужно.
Чтобы обеспечить возможность запуска нескольких процессов одновременно, Android устанавливает жесткое ограничение на размер кучи, выделяемый для каждого приложения. Точное ограничение размера кучи варьируется в зависимости от устройства и общего объема доступной оперативной памяти. Если ваше приложение достигает предела емкости кучи и пытается выделить больше памяти, система выдает ошибку OutOfMemoryError .
Чтобы избежать нехватки памяти, вы можете запросить у системы информацию о доступном объеме памяти на текущем устройстве, вызвав метод getMemoryInfo . Этот метод возвращает объект ActivityManager.MemoryInfo , предоставляющий информацию о текущем состоянии памяти устройства, включая доступную память, общий объем памяти и пороговое значение памяти — уровень памяти, при котором система начинает останавливать процессы. Объект ActivityManager.MemoryInfo также предоставляет lowMemory , представляющий собой логическое значение, указывающее, не хватает ли памяти на устройстве.
Приведённый ниже фрагмент кода демонстрирует, как использовать метод getMemoryInfo в вашем приложении.
fun doSomethingMemoryIntensive() {
// Before doing something that requires a lot of memory,
// check whether the device is in a low memory state.
if (!getAvailableMemory().lowMemory) {
// Do memory intensive work.
}
}
// Get a MemoryInfo object for the device's current memory status.
private fun getAvailableMemory(): ActivityManager.MemoryInfo {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
return ActivityManager.MemoryInfo().also { memoryInfo ->
activityManager.getMemoryInfo(memoryInfo)
}
}
Мониторинг ошибок, связанных с нехваткой памяти
Заметные для пользователя завершения процессов при низком уровне памяти (LMK) происходят, когда системная память становится критически низкой. При низком уровне памяти демон lmkd (демон завершения процессов при низком уровне памяти) завершает процессы на основе их oom_adj_score . Приложения, которые кэшируются или запускают службу без связанного пользовательского интерфейса (например, задание), имеют самые высокие значения и завершаются первыми. Если уровень памяти остается критически низким, демон вынужден освобождать память у процессов со значением oom_adj_score равным 0. Поскольку это значение зарезервировано для видимых приложений, их завершение приводит к немедленному, некорректному завершению процесса. Для конечного пользователя это выглядит как сбой приложения, часто обходящий стандартные механизмы сохранения состояния жизненного цикла и приводящий к потере прогресса пользователя.
В Android Vitals основное внимание уделяется завершению процессов, находящихся на переднем плане, поскольку это высокоточный индикатор некорректного управления памятью. Хотя показатель LMK выше 1% указывает на критическую необходимость немедленных действий, низкий показатель не обязательно свидетельствует о состоянии системы. Низкий показатель LMK, воспринимаемый пользователем, может означать, что демон LMK часто завершает процессы, находящиеся в фоновом режиме, что ухудшает производительность при «теплом старте» и плавность многозадачности. Поэтому мы рекомендуем придерживаться лучших практик использования памяти независимо от текущего показателя LMK, чтобы обеспечить долгосрочную стабильность и работоспособность устройства.
Используйте ProfilingManager для отслеживания проблем с памятью.
Платформа Android предоставляет ProfilingManager — расширенный API для мониторинга, позволяющий собирать пользовательские данные в рабочей среде на основе заданных вами триггеров. Это может помочь выявить трудновоспроизводимые проблемы с памятью.
Два триггера, появившиеся в Android 17 , особенно полезны для выявления проблем с памятью:
-
TRIGGER_TYPE_OOMуказывает на то, что приложение вызвало ошибкуOutOfMemoryError. Она срабатывает при следующем запуске приложения после сбоя, когда приложение регистрируется для запуска профилирования. -
TRIGGER_TYPE_ANOMALYсрабатывает, когда система обнаруживает аномальное поведение приложения. В частности, это может быть вызвано чрезмерным использованием памяти. TRIGGER_TYPE_ANOMALY срабатывает после того, как приложение продемонстрировало чрезмерное использование памяти, и до того, как система предпримет какие-либо действия для остановки проблемного процесса. Например, если приложение превышает лимиты памяти, введенные в Android 17 ,TRIGGER_TYPE_ANOMALYсрабатывает перед тем, как система завершит работу приложения.
Для получения дополнительной информации об использовании ProfilingManager для программной регистрации и получения триггеров см. документацию по профилированию на основе триггеров . Firebase Crashlytics также поддерживает триггеры TRIGGER_TYPE_OOM и TRIGGER_TYPE_ANOMALY , сопоставляя их с другими диагностическими метаданными.
Вы также можете использовать профилирование, управляемое приложением, для ручного определения начальной и конечной точек трассировки. Мы рекомендуем делать это для ручного создания дампов или профилей кучи в областях, где вы подозреваете утечки памяти или чрезмерное использование памяти.
Отслеживание состояния процесса и использования памяти.
Помимо обратных вызовов к памяти и событий, вы можете явно запрашивать состояние и приоритет процессов вашего приложения. Это особенно полезно для понимания того, как операционная система классифицирует текущее состояние вашего приложения (например, находится ли оно на переднем плане, воспринимается пользователем или кэшируется) и существует ли риск его принудительного завершения из-за нехватки памяти.
Панель мониторинга на Python для непрерывного мониторинга.
Используйте скрипт Android Memory Monitor на Python во время работы вашего приложения для непрерывного мониторинга процессов и используемой памяти. Это инструмент командной строки, использующий команды adb для отображения панелей мониторинга в терминале и веб-интерфейсе, которые помогут вам понять состояние и использование памяти процессами вашего приложения. Чтобы запустить панели мониторинга, запустите скрипт, указав имя пакета вашего приложения:
python3 android_mem_monitor.py your.package.name
Подробные инструкции по использованию функций панели мониторинга см. в файле README или во встроенных комментариях скрипта.
Во время выполнения с помощью ActivityManager
Чтобы получить информацию о запущенных процессах во время выполнения, вы можете запросить ActivityManager.getRunningAppProcesses . Это вернет список объектов, содержащих основную информацию о каждом из процессов вашего приложения. Поле importance указывает относительную важность, которую система придает процессу, и соответствует таким константам, как:
-
IMPORTANCE_FOREGROUND: Процесс активно выполняет работу пользовательского интерфейса на переднем плане. -
IMPORTANCE_FOREGROUND_SERVICE: Процесс запускает службу переднего плана (например, активную фоновую музыку или большие загрузки), которая является примером службы, воспринимаемой пользователем. -
IMPORTANCE_CACHED: Этот процесс содержит кэшированный код. Процесс заморожен, и его неиспользуемая память освобождается Android. В этом состоянииMemoryLimiterОС не завершит работу приложения из-за превышения порогового значения памяти, специфичного для приложения. Однако, если в системе в целом не хватает памяти, приложение является основным кандидатом на завершение работы при нехватке памяти.
Для отладки с помощью adb
При отладке поведения памяти и жизненных циклов процессов вы также можете использовать команды adb для исследования оценок нехватки памяти (OOM) и объема используемой памяти в режиме реального времени. Для мониторинга процессов и состояний памяти вашего приложения можно использовать следующие команды:
- Найдите активные идентификаторы процессов (PID): Сначала найдите все процессы, которые в данный момент запущены вашим приложением, используя команду
ps, отфильтрованную по имени вашего пакета.
shell adb shell ps -A | grep your.package.name - Проверьте текущий показатель нехватки памяти (OOM): используйте PID процесса, чтобы прочитать его показатель OOM из файловой системы процесса. Показатель от 0 до 199 обычно указывает на приложение, работающее на переднем плане, от 200 до 249 — на видимую службу, от 250 до 899 — на фоновую службу, а показатели 900 и выше означают, что процесс кэширован и, вероятно, будет завершен.
shell adb shell cat /proc/ pid /oom_score_adj - Непрерывный мониторинг оценок нехватки памяти (OOM Score): Для непрерывного мониторинга изменений оценки нехватки памяти приложения (которая будет представлять собой наименьшую оценку нехватки памяти среди всех его процессов) можно использовать команду
watch-uids.
shell adb shell am watch-uids - Измерение объема используемой памяти: Чтобы быстро оценить объем используемой памяти процессом, например, использование анонимного RSS-канала и файла подкачки , считайте его состояние непосредственно из файловой системы процесса Linux.
shell adb shell cat /proc/ pid /status | grep -E "VmRSS|RssAnon|VmSwap"
Для получения более подробной и полной информации о выделении памяти используйте командуdumpsys meminfo:
shell adb shell dumpsys meminfo pid - Исследуйте активные компоненты: если ваш процесс поддерживает неожиданно высокий приоритет (например, остается с показателем нехватки памяти
200вместо перехода в кэш), вы можете точно определить, что именно он запускает. Командаdumpsys activity processesпоказывает конкретные действия, службы, поставщиков и получателей, поддерживающие процесс в рабочем состоянии.
shell adb shell dumpsys activity processes your.package.name
Используйте более эффективные с точки зрения использования памяти конструкции кода.
Некоторые функции Android, классы Java и конструкции кода используют больше памяти, чем другие. Вы можете минимизировать объем памяти, используемый вашим приложением, выбирая более эффективные альтернативы в своем коде.
Пользуйтесь услугами экономно.
Мы настоятельно рекомендуем не оставлять службы запущенными без необходимости. Запуск ненужных служб — одна из самых серьезных ошибок в управлении памятью, которую может допустить Android-приложение. Если вашему приложению необходима служба для работы в фоновом режиме, не оставляйте ее запущенной, если только ей не требуется выполнить какую-либо задачу. Остановите службу, когда она завершит свою задачу. В противном случае это может привести к утечке памяти.
При запуске службы система предпочитает поддерживать процесс этой службы в рабочем состоянии. Такое поведение делает процессы служб очень затратными, поскольку оперативная память, используемая службой, остается недоступной для других процессов. Это уменьшает количество кэшированных процессов, которые система может хранить в LRU-кэше, что снижает эффективность переключения приложений. Это может даже привести к перегрузке системы, когда памяти не хватает и система не может поддерживать достаточное количество процессов для размещения всех запущенных в данный момент служб.
Как правило, следует избегать использования постоянных служб из-за постоянной нагрузки на доступную память. Вместо этого мы рекомендуем использовать альтернативную реализацию, например WorkManager . Дополнительную информацию о том, как использовать WorkManager для планирования фоновых процессов, см. в разделе «Планирование задач» .
Используйте оптимизированные контейнеры данных.
Некоторые классы, предоставляемые языком программирования, не оптимизированы для использования на мобильных устройствах. Например, универсальная реализация HashMap может быть неэффективной с точки зрения использования памяти, поскольку для каждого отображения требуется отдельный объект записи.
Фреймворк Android включает в себя несколько оптимизированных контейнеров данных, в том числе SparseArray , SparseBooleanArray и LongSparseArray . Например, классы SparseArray более эффективны, поскольку они избавляют систему от необходимости автоматической упаковки ключа, а иногда и значения, что приводит к созданию еще одного или двух объектов для каждой записи.
При необходимости вы всегда можете перейти к использованию массивов без дополнительных параметров для получения более компактной структуры данных.
Будьте осторожны с абстракциями кода.
Разработчики часто используют абстракции как хорошую практику программирования, поскольку они могут повысить гибкость кода и упростить его сопровождение. Однако абстракции, как правило, требуют выполнения большего объема кода. Как подробно описано в статье «Сокращение объема кода и ресурсов вашего приложения» , больший объем скомпилированного кода напрямую увеличивает объем физической оперативной памяти, необходимой вашему приложению. Если ваши абстракции не приносят существенной пользы, избегайте их.
Используйте облегченные протобуфы для сериализованных данных.
Протоколы буферизации (protobufs) — это независимый от языка программирования, платформы и расширяемый механизм, разработанный Google для сериализации структурированных данных — аналогичный XML или JSON, но меньшего размера, более быстрый и простой. Если вы используете protobufs для своих данных, всегда используйте облегченные версии protobufs в клиентском коде. Обычные protobufs генерируют чрезвычайно многословный код, что увеличивает объем кода вашего приложения в оперативной памяти (см. «Уменьшение объема кода и ресурсов вашего приложения ») и способствует увеличению размера APK-файла.
Для получения более подробной информации см. файл readme протокола protobuf .
Будьте осторожны с утечками памяти.
Неправильное управление ссылками может привести к утечкам памяти, когда объекты превышают свой полезный срок службы, препятствуя сборщику мусора освободить память, занятую утекшим объектом. Чтобы избежать утечек памяти, следует внедрять проектирование с учетом жизненного цикла.
Избегайте перегрузки памяти.
События сборки мусора не влияют на производительность вашего приложения. Однако большое количество событий сборки мусора, происходящих в течение короткого промежутка времени, может быстро разрядить батарею, а также незначительно увеличить время установки кадров из-за необходимого взаимодействия между сборщиком мусора и потоками приложения. Чем больше времени система тратит на сборку мусора, тем быстрее разряжается батарея.
Часто обновление памяти может приводить к большому количеству событий сборки мусора. На практике обновление памяти описывает количество выделенных временных объектов, которые появляются за определенный промежуток времени.
Например, вы можете выделить несколько временных объектов внутри цикла for . Или вы можете создать экземпляры Brush , Path или объектов форматирования данных во время перекомпозиции компонуемого объекта или внутри вызова DrawScope (например, Canvas ). В обоих случаях приложение быстро создает множество объектов. Они могут быстро занять всю доступную память в молодом поколении, что приведет к запуску сборки мусора.
Используйте профилировщик памяти , чтобы найти в вашем коде места с высокой частотой использования памяти и исправить их.
После выявления проблемных областей в коде постарайтесь уменьшить количество выделений памяти в критически важных с точки зрения производительности областях. Рассмотрите возможность переноса этих операций из внутренних циклов или, возможно, их размещения в структуре выделения памяти на основе фабрики .
Вы также можете оценить, насколько полезны пулы объектов в данном сценарии использования. В случае с пулом объектов, вместо того чтобы просто выбросить экземпляр объекта, вы освобождаете его в пуле после того, как он больше не нужен. В следующий раз, когда потребуется экземпляр объекта этого типа, вы сможете получить его из пула, а не выделять его отдельно.
Тщательно оцените производительность, чтобы определить, подходит ли пул объектов в данной ситуации. В некоторых случаях пулы объектов могут ухудшить производительность. Хотя пулы позволяют избежать выделения памяти, они вводят другие накладные расходы. Например, поддержание пула обычно включает синхронизацию, которая имеет существенные накладные расходы. Кроме того, очистка экземпляра объекта в пуле во избежание утечек памяти во время освобождения и последующая инициализация во время получения могут иметь ненулевые накладные расходы.
Сохранение в пуле большего количества экземпляров объектов, чем необходимо, также создает нагрузку на сборщик мусора. Хотя пулы объектов уменьшают количество вызовов сборки мусора, в конечном итоге они увеличивают объем работы, необходимой для каждого вызова, поскольку он пропорционален количеству доступных (активных) байтов.