Управляйте памятью вашего приложения.

На этой странице объясняется, как заблаговременно сократить использование памяти в вашем приложении. Информацию о том, как операционная система 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 или Dagger 2.

Фреймворки внедрения зависимостей могут упростить написание кода и предоставить адаптивную среду, полезную для тестирования и других изменений конфигурации.

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

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

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

Подходите к загрузке изображений осознанно.

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

Например, большинство растровых изображений используют конфигурацию ARGB_8888 , что означает, что каждому пикселю требуется 4 байта памяти — по одному байту для красного, зеленого, синего и альфа-канала (прозрачности). Если у вас есть JPEG-файл размером 100 КБ, и вы отображаете его в окне 1000×1000 пикселей, то для каждого из этих 1 000 000 пикселей потребуется 4 байта, что в сумме составит 4 МБ памяти.

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

Отслеживание доступной памяти и её использования.

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

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

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

Освобождение памяти в ответ на события

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) {

        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.
        }
    }
}

Java

import android.content.ComponentCallbacks2;
// Other import statements.

public class MainActivity extends AppCompatActivity
    implements 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.
     */
    public void onTrimMemory(int 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.
        }
    }
}

Проверьте, сколько памяти вам нужно.

Чтобы обеспечить возможность запуска нескольких процессов одновременно, 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)
    }
}

Java

public void doSomethingMemoryIntensive() {

    // Before doing something that requires a lot of memory,
    // check whether the device is in a low memory state.
    ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();

    if (!memoryInfo.lowMemory) {
        // Do memory intensive work.
    }
}

// Get a MemoryInfo object for the device's current memory status.
private ActivityManager.MemoryInfo getAvailableMemory() {
    ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    activityManager.getMemoryInfo(memoryInfo);
    return 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 , сопоставляя их с другими диагностическими метаданными.

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

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

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

Во время выполнения с помощью 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, но меньшего размера, более быстрый и простой. Если вы используете protobufs для своих данных, всегда используйте облегченные версии protobufs в клиентском коде. Обычные protobufs генерируют чрезвычайно многословный код, что увеличивает объем кода вашего приложения в оперативной памяти (см. « Уменьшение объема кода и ресурсов вашего приложения ») и способствует увеличению размера APK-файла.

Для получения более подробной информации см. файл readme протокола protobuf .

Будьте осторожны с утечками памяти.

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

Избегайте перегрузки памяти.

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

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

Например, вы можете выделить несколько временных объектов внутри цикла for . Или вы можете создать новые объекты Paint или Bitmap внутри функции onDraw() представления. В обоих случаях приложение быстро создает множество объектов в большом объеме. Это может быстро занять всю доступную память в молодом поколении, что приведет к запуску сборки мусора.

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

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

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

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

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