Рекомендации по управлению памятью

В этом документе предполагается, что вы следовали рекомендациям по управлению памятью для приложений Android, например « Управление памятью вашего приложения» .

Введение

Утечка памяти — это тип утечки ресурсов, который возникает, когда компьютерная программа не освобождает выделенную память, которая больше не нужна. Утечка может привести к тому, что приложение запросит у ОС больше памяти, чем доступно, и, таким образом, приведет к сбою приложения. Ряд неправильных действий может привести к утечкам памяти в приложениях Android, например неправильное удаление ресурсов или отмена регистрации прослушивателей, когда они больше не нужны.

В этом документе представлены некоторые рекомендации, которые помогут предотвратить, обнаружить и устранить утечки памяти в вашем коде. Если вы опробовали методы, описанные в этом документе, и подозреваете утечку памяти в наших SDK, см. раздел Как сообщить о проблемах с Google SDK .

Прежде чем обращаться в службу поддержки

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

Предотвращение утечек памяти

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

Рекомендации для приложений Android

Убедитесь, что вы выполнили все следующие действия в своем приложении для Android:

  1. Освободите неиспользуемые ресурсы .
  2. Отмените регистрацию прослушивателей, когда они больше не нужны .
  3. Отменяйте задачи, когда они не нужны .
  4. Перенаправить методы жизненного цикла для освобождения ресурсов .
  5. Используйте последние версии SDK

Подробные сведения о каждом из этих методов см. в следующих разделах.

Освободите неиспользуемые ресурсы

Если ваше приложение Android использует ресурс, обязательно освободите его, когда он больше не нужен. Если вы этого не сделаете, ресурс продолжит занимать память даже после того, как ваше приложение завершит работу с ним. Дополнительные сведения см. в разделе Жизненный цикл активности в документации Android.

Выпустить устаревшие ссылки GoogleMap в GeoSDK.

Распространенной ошибкой является то, что GoogleMap может вызвать утечку памяти, если он кэшируется с помощью NavigationView или MapView. GoogleMap имеет отношение 1 к 1 с NavigationView или MapView, из которого он извлекается. Вы должны либо убедиться, что GoogleMap не кэшируется, либо что ссылка освобождается при вызове NavigationView#onDestroy или MapView#onDestroy. Если вы используете NavigationSupportFragment, MapSupportFragment или собственный фрагмент, обертывающий эти представления, ссылку необходимо освободить в Fragment#onDestroyView.

class NavFragment : SupportNavigationFragment() {

  var googleMap: GoogleMap?

  override fun onCreateView(
    inflater: LayoutInflater,
    parent: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View  {
    super.onCreateView(inflater,parent,savedInstanceState)
    getMapAsync{map -> googleMap = map}
  }

  override fun onDestroyView() {
    googleMap = null
  }
}

Отменить регистрацию прослушивателей, когда они больше не нужны

Когда ваше приложение Android регистрирует прослушиватель для события, например нажатия кнопки или изменения состояния представления, обязательно отмените регистрацию прослушивателя, когда приложению больше не нужно отслеживать событие. Если вы этого не сделаете, слушатели продолжат занимать память даже после того, как ваше приложение завершится с ними.

Например, предположим, что ваше приложение использует Navigation SDK и вызывает следующий прослушиватель для прослушивания событий прибытия: метод addArrivalListener для прослушивания событий прибытия; он также должен вызывать removeArrivalListener , когда больше не нужно отслеживать события прибытия.

var arrivalListener: Navigator.ArrivalListener? = null

fun registerNavigationListeners() {
  arrivalListener =
    Navigator.ArrivalListener {
      ...
    }
  navigator.addArrivalListener(arrivalListener)
}

override fun onDestroy() {
  navView.onDestroy()
  if (arrivalListener != null) {
    navigator.removeArrivalListener(arrivalListener)
  }

  ...
  super.onDestroy()
}

Отменяйте задачи, когда они не нужны

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

Дополнительные сведения о рекомендациях см. в разделе «Управление памятью приложения» документации Android.

Методы прямого жизненного цикла для освобождения ресурсов

Если ваше приложение использует SDK навигации или карт, обязательно освободите ресурсы, передав методы жизненного цикла (выделены жирным шрифтом) в navView . Это можно сделать с помощью NavigationView в Navigation SDK или MapView в Maps или Navigation SDK. Вы также можете использовать SupportNavigationFragment или SupportMapFragment вместо непосредственного использования NavigationView и MapView соответственно. Фрагменты поддержки обрабатывают пересылку методов жизненного цикла.

class NavViewActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    navView = ...
    navView.onCreate(savedInstanceState)
    ...
  }

  override fun onSaveInstanceState(savedInstanceState: Bundle) {
    super.onSaveInstanceState(savedInstanceState)
    navView.onSaveInstanceState(savedInstanceState)
  }

  override fun onTrimMemory(level: Int) {
    super.onTrimMemory(level)
    navView.onTrimMemory(level)
  }

  /* Same with
    override fun onStart()
    override fun onResume()
    override fun onPause()
    override fun onConfigurationChanged(...)
    override fun onStop()
    override fun onDestroy()
  */
}

Используйте последние версии SDK

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

Устранение утечек памяти

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

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

Для устранения утечек памяти выполните следующий процесс:

  1. Воссоздайте проблему . Этот шаг необходим для его отладки.
  2. Проверьте, ожидается ли использование памяти . Убедитесь, что увеличение использования, которое выглядит как утечка, на самом деле не является объемом памяти, необходимым для запуска вашего приложения.
  3. Отладка на высоком уровне . Существует несколько утилит, которые можно использовать для отладки. Три различных стандартных набора инструментов помогают устранять проблемы с памятью в Android: Android Studio, Perfetto и утилиты командной строки Android Debug Bridge (adb).
  4. Проверьте использование памяти вашим приложением . Получите дамп кучи и отслеживание распределения, а затем проанализируйте его.
  5. Исправление утечек памяти .

В следующих разделах эти шаги подробно описаны.

Шаг 1. Воссоздайте проблему

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

  • Какой набор функций активирован?

  • Какая конкретная последовательность действий пользователя вызывает утечку?

    • Пробовали ли вы несколько раз активировать эту последовательность?
  • Какие состояния жизненного цикла прошло приложение?

    • Пробовали ли вы несколько итераций в разных состояниях жизненного цикла?

Убедитесь, что вы можете воссоздать проблему в последней версии SDK. Проблема из предыдущей версии, возможно, уже устранена.

Шаг 2. Проверьте, ожидается ли использование памяти приложением.

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

  • Вероятна утечка: активация сценария посредством нескольких итераций со временем приводит к увеличению использования памяти.

  • Вероятное ожидаемое использование памяти : память освобождается после остановки сценария.

  • Возможное ожидаемое использование памяти : использование памяти увеличивается в течение определенного периода времени, а затем снижается. Это может быть связано с ограниченным кэшем или другим ожидаемым использованием памяти.

Если поведение приложения, вероятно, связано с ожидаемым использованием памяти, проблему можно решить, управляя памятью вашего приложения. Дополнительную информацию см. в разделе Управление памятью приложения .

Шаг 3. Отладка на высоком уровне

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

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

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

Счетчики памяти Perfetto

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

Perfetto user interface

Утилиты командной строки моста отладки Android (adb)

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

  • Meminfo позволяет просматривать подробную информацию о памяти в определенный момент времени.

  • Procstats предоставляет некоторые важные агрегированные статистические данные за определенный период времени.

Важнейшей статистикой, на которую следует обратить внимание, является максимальный объем физической памяти (maxRSS), который требуется приложению с течением времени. MaxPSS может быть не таким точным. Чтобы повысить точность, см. флаг adb shell dumpsys procstats --help –start-testing .

Отслеживание распределения

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

Шаг 4. Проверьте использование памяти вашим приложением с помощью дампа кучи

Один из способов обнаружить утечку памяти — получить дамп кучи вашего приложения, а затем проверить его на наличие утечек. Дамп кучи — это снимок всех объектов в памяти приложения. Его можно использовать для диагностики утечек памяти и других проблем, связанных с памятью.

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

  1. Захват дампа кучи .
  2. Анализ дампа кучи на предмет утечек памяти .
  3. Исправление утечек памяти .

Подробную информацию см. в следующих разделах.

Захват дампа кучи

Чтобы записать дамп кучи, вы можете использовать Android Debug Bridge (adb) или профилировщик памяти Android Studio.

Используйте adb для создания дампа кучи

Чтобы записать дамп кучи с помощью adb , выполните следующие действия:

  1. Подключите Android-устройство к компьютеру.
  2. Откройте командную строку и перейдите в каталог, где находятся инструменты adb.
  3. Чтобы получить дамп кучи, выполните следующую команду:

    adb shell am dumpheap my.app.name $PHONE_FILE_OUT

  4. Чтобы получить дамп кучи, выполните следующую команду:

    adb pull $PHONE_FILE_OUT $LOCAL_FILE.

Используйте Android Studio для записи дампа кучи

Чтобы записать дамп кучи с помощью профилировщика памяти Android Studio, выполните следующие действия в разделе «Захват кучи Android».

Анализ дампа кучи на предмет утечек памяти.

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

  1. Откройте свой проект Android в Android Studio.

  2. Выберите «Выполнить» , а затем выберите конфигурацию «Отладка» .

  3. Откройте вкладку «Профилировщик Android» .

  4. Выберите Память .

  5. Выберите Открыть дамп кучи и выберите созданный вами файл дампа кучи. Профилировщик памяти отображает график использования памяти вашим приложением.

  6. Используйте график для анализа дампа кучи:

    • Определите объекты, которые больше не используются.

    • Определите объекты, которые используют много памяти.

    • Посмотрите, сколько памяти использует каждый объект.

  7. Используйте эту информацию, чтобы сузить круг вопросов или найти источник утечки памяти и устранить его.

Шаг 5. Устраните утечки памяти

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

Другие инструменты отладки

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

Отладочная память в машинном коде с отслеживанием распределения

Даже если вы не используете собственный код напрямую, некоторые распространенные библиотеки Android, включая Google SDK, используют его. Если вы считаете, что утечка памяти произошла в машинном коде, есть несколько инструментов, которые вы можете использовать для ее отладки. Отслеживание выделения памяти с помощью Android Studio или heapprofd (также совместимого с Perfetto) — отличный способ выявить потенциальные причины утечки памяти и зачастую самый быстрый способ отладки.

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

Выявляйте утечки с помощью LeakCanary

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

Как сообщить о проблемах с Google SDK

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

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

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

  • Если ожидается утечка собственной памяти , поделитесь результатами отслеживания выделения из heapprofd .

  • Отчет об ошибке , полученный после воссоздания условия утечки.

  • Сложите следы любых сбоев, связанных с памятью .

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