В этом документе предполагается, что вы следовали рекомендациям по управлению памятью для приложений Android, например, разделу «Управление памятью вашего приложения» .
Введение
Утечка памяти — это тип утечки ресурсов, возникающий, когда компьютерная программа не освобождает выделенную память, которая больше не нужна. Утечка может привести к тому, что приложение запросит у операционной системы больше памяти, чем у него есть в наличии, что приведет к сбою приложения. Ряд неправильных действий может вызывать утечки памяти в приложениях Android, например, неправильное освобождение ресурсов или неотмена регистрации слушателей, когда они больше не нужны.
В этом документе представлены некоторые рекомендации по предотвращению, обнаружению и устранению утечек памяти в вашем коде. Если вы попробовали методы, описанные в этом документе, и подозреваете утечку памяти в наших SDK, см. раздел «Как сообщать о проблемах с Google SDK» .
Прежде чем обращаться в службу поддержки
Прежде чем сообщать о проблеме утечки памяти в службу поддержки Google, следуйте рекомендациям и шагам отладки, описанным в этом документе, чтобы убедиться, что ошибка не в вашем коде. Эти шаги могут решить вашу проблему, а если нет, то предоставят службе поддержки Google необходимую информацию для оказания вам помощи.
Предотвращение утечек памяти
Следуйте этим рекомендациям, чтобы избежать наиболее распространенных причин утечек памяти в коде, использующем SDK Google.
Рекомендации по разработке приложений для Android
Убедитесь, что вы выполнили все следующие действия в своем Android-приложении:
- Освободите неиспользуемые ресурсы .
- Отменяйте регистрацию слушателей, когда они больше не нужны .
- Отменяйте задачи, когда они не нужны .
- Использование методов управления жизненным циклом для высвобождения ресурсов .
- Используйте последние версии SDK .
- Во избежание ошибок ANR избегайте блокировки основного потока во время инициализации .
Подробную информацию о каждой из этих практик см. в следующих разделах.
Освободите неиспользуемые ресурсы
Когда ваше Android-приложение использует ресурс, обязательно освобождайте его, когда он больше не нужен. В противном случае ресурс продолжит занимать память даже после того, как ваше приложение завершит его использование. Для получения дополнительной информации ознакомьтесь с разделом «Жизненный цикл активности» в документации Android.
Удалите устаревшие ссылки на Google Maps из GeoSDK.
Распространенная ошибка заключается в том, что кэширование GoogleMap с использованием NavigationView или MapView может привести к утечке памяти. GoogleMap имеет отношение «один к одному» с 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 в SDK навигации или MapView в 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.
SDK от Google постоянно обновляются, в них добавляются новые функции, исправляются ошибки и повышается производительность. Поддерживайте SDK в своем приложении в актуальном состоянии, чтобы получать эти исправления.
Избегайте блокировки основного потока во время инициализации, чтобы предотвратить ошибки ANR.
Когда приложение блокирует основной поток слишком долго, это может привести к ошибке "Приложение не отвечает" (ANR). Чтобы предотвратить ошибки ANR, следует максимально упростить методы жизненного цикла, такие как onCreate() , откладывая выполнение длительных задач или запуская их вне основного потока.
Чтобы избежать ошибок ANR, связанных с инициализацией SDK:
- За один раз можно создавать только один экземпляр карты.
- При создании экземпляра карты по возможности сведите к минимуму нагрузку на поток пользовательского интерфейса.
Отладка утечек памяти
Если после применения всех предложенных ранее рекомендаций, описанных в этом документе, утечки памяти по-прежнему сохраняются, выполните следующие действия для отладки.
Прежде чем начать , вам следует ознакомиться с тем, как Android управляет памятью. Для получения дополнительной информации прочтите обзор управления памятью в Android.
Для устранения утечек памяти выполните следующие действия:
- Воспроизведите проблему . Этот шаг необходим для её отладки.
- Проверьте, соответствует ли использование памяти ожидаемому уровню . Убедитесь, что повышенное использование, которое кажется утечкой, на самом деле не является объемом памяти, необходимым для работы вашего приложения.
- Отладка на высоком уровне . Существует несколько утилит, которые можно использовать для отладки. Три различных стандартных набора инструментов помогают отлаживать проблемы с памятью в Android: Android Studio, Perfetto и утилиты командной строки Android Debug Bridge (adb).
- Проверьте использование памяти вашим приложением . Получите дамп кучи и отслеживайте выделение памяти, а затем проанализируйте их.
- Устраните утечки памяти .
В следующих разделах эти шаги описаны подробно.
Шаг 1: Воспроизведите проблему.
Если вам не удалось воспроизвести проблему, сначала рассмотрите сценарии, которые могут привести к утечке памяти. Если вы уверены, что проблема воспроизводится, можно сразу перейти к анализу дампа памяти. Однако, если дамп памяти появляется только при запуске приложения или в другой случайный момент времени, возможно, вы не активировали условия, которые могли бы вызвать утечку. Рассмотрите различные сценарии при попытке воспроизвести проблему:
Какой набор функций активирован?
Какая именно последовательность действий пользователя приводит к утечке данных?
- Вы пробовали активировать эту последовательность несколько раз?
Через какие стадии жизненного цикла прошло приложение?
- Вы пробовали несколько итераций на разных этапах жизненного цикла?
Убедитесь, что вы можете воспроизвести проблему в последней версии SDK. Проблема из предыдущей версии, возможно, уже исправлена.
Шаг 2: Проверьте, соответствует ли использование памяти приложением ожидаемым показателям.
Каждая функция требует дополнительной памяти. При отладке различных сценариев следует учитывать, является ли это ожидаемым использованием памяти или же это утечка памяти. Например, для разных функций или пользовательских задач можно рассмотреть следующие варианты:
Вероятнее всего, утечка памяти: активация сценария в нескольких итерациях приводит к увеличению использования памяти с течением времени.
Вероятное ожидаемое использование памяти : память освобождается после остановки сценария.
Возможно, ожидаемое использование памяти : использование памяти увеличивается в течение некоторого времени, а затем постепенно снижается. Это может быть связано с ограниченным объемом кэша или другими ожидаемыми факторами использования памяти.
Если такое поведение приложения, вероятно, является следствием ожидаемого использования памяти, проблему можно решить, управляя памятью приложения. Для получения помощи см. раздел «Управление памятью приложения» .
Шаг 3: Отладка на высоком уровне
При отладке утечки памяти начинайте с общего уровня, а затем углубляйтесь в детали, когда сузите круг возможных причин. Используйте один из этих инструментов высокоуровневой отладки, чтобы сначала проанализировать, есть ли утечка со временем:
Android Studio Memory Profiler (рекомендуется)
Профайлер памяти Android Studio
Этот инструмент предоставляет визуальную гистограмму используемой памяти. С помощью этого же интерфейса можно создавать дампы кучи и отслеживать выделение памяти. Этот инструмент рекомендуется по умолчанию. Для получения дополнительной информации см. раздел «Профилировщик памяти Android Studio» .
Счетчики памяти Perfetto
Perfetto предоставляет точный контроль над отслеживанием нескольких метрик и отображает все данные в виде единой гистограммы. Для получения дополнительной информации см. раздел «Счетчики памяти Perfetto» .

Утилиты командной строки Android debug bridge (adb)
Многое из того, что можно отслеживать с помощью Perfetto, также доступно в виде утилиты командной строки adb , которую можно запрашивать напрямую. Вот несколько важных примеров:
Meminfo позволяет просмотреть подробную информацию о памяти в определенный момент времени.
Procstats предоставляет ряд важных сводных статистических данных за определенный период времени.
Ключевым показателем здесь является максимальный объем физической памяти, необходимый приложению с течением времени (maxRSS). Показатель maxPSS может быть не таким точным. Для повышения точности см. флаг adb shell dumpsys procstats --help –start-testing .
Отслеживание распределения
Отслеживание выделения памяти позволяет определить трассировку стека, в которой была выделена память и не была ли она освобождена. Этот шаг особенно полезен при поиске утечек памяти в нативном коде. Поскольку этот инструмент определяет трассировку стека, он может стать отличным средством для быстрой отладки первопричины или для выяснения того, как воспроизвести проблему. Инструкции по использованию отслеживания выделения памяти см. в разделе «Отладка памяти в нативном коде с помощью отслеживания выделения памяти» .
Шаг 4: Проверьте использование памяти вашим приложением с помощью дампа кучи.
Один из способов обнаружения утечек памяти — это получение дампа кучи вашего приложения и последующий его анализ на наличие утечек. Дамп кучи — это снимок всех объектов в памяти приложения. Его можно использовать для диагностики утечек памяти и других проблем, связанных с памятью.
Android Studio может обнаруживать утечки памяти, которые сборщик мусора не может исправить. При захвате дампа кучи Android Studio проверяет, есть ли активность или фрагмент, которые все еще доступны, но уже были уничтожены.
- Создайте дамп памяти .
- Проанализируйте дамп кучи, чтобы обнаружить утечки памяти .
- Устраните утечки памяти .
Более подробная информация содержится в следующих разделах.
Создание дампа кучи
Для создания дампа памяти можно использовать Android Debug Bridge (adb) или Android Studio Memory Profiler.
Используйте adb для создания дампа кучи.
Чтобы получить дамп кучи с помощью adb , выполните следующие действия:
- Подключите ваше устройство Android к компьютеру.
- Откройте командную строку и перейдите в каталог, где находятся инструменты adb.
Для создания дампа памяти выполните следующую команду:
adb shell am dumpheap my.app.name $PHONE_FILE_OUTДля получения дампа кучи выполните следующую команду:
adb pull $PHONE_FILE_OUT $LOCAL_FILE.
Используйте Android Studio для создания дампа памяти.
Чтобы создать дамп памяти с помощью профилировщика памяти Android Studio, выполните следующие действия, описанные в разделе « Создание дампа памяти в Android».
Проанализируйте дамп кучи, чтобы обнаружить утечки памяти.
После получения дампа памяти вы можете использовать профилировщик памяти Android Studio для его анализа. Для этого выполните следующие шаги:
Откройте свой Android-проект в Android Studio.
Выберите «Выполнить» , а затем выберите конфигурацию «Отладка» .
Откройте вкладку «Профилировщик Android» .
Выберите память .
Выберите «Открыть дамп кучи» и выберите созданный вами файл дампа кучи. Профилировщик памяти отобразит график использования памяти вашим приложением.
Используйте график для анализа дампа памяти:
Выявите предметы, которые больше не используются.
Выявите объекты, которые используют много памяти.
Посмотрите, сколько памяти использует каждый объект.
Используйте эту информацию, чтобы сузить круг поиска или найти источник утечки памяти и устранить её.
Шаг 5: Устранение утечек памяти
Как только вы определите источник утечки памяти, вы сможете её устранить. Исправление утечек памяти в ваших Android-приложениях помогает улучшить производительность и стабильность ваших приложений. В зависимости от ситуации, детали могут различаться. Однако следующие рекомендации могут помочь:
Убедитесь, что ваше приложение выделяет и освобождает память в соответствии с рекомендациями, приведенными в разделе «Управление памятью вашего приложения» на Android.
Удалите неиспользуемый код или ресурсы из вашего приложения. Подробную информацию для приложений Android см. в разделе «Рекомендации по разработке приложений Android» .
Другие инструменты отладки
Если после выполнения этих шагов вам так и не удалось найти и устранить утечку памяти, попробуйте следующие инструменты:
- Отладка памяти в нативном коде с отслеживанием выделения памяти .
- Выявляйте утечки с помощью LeakCanary .
Отладка памяти в нативном коде с отслеживанием выделения памяти
Даже если вы не используете нативный код напрямую, несколько распространенных библиотек Android, включая SDK Google, его используют. Если вы считаете, что утечка памяти находится в нативном коде, то для отладки можно использовать несколько инструментов . Отслеживание выделения памяти с помощью Android Studio или heapprofd (также совместимого с Perfetto) — отличный способ выявить потенциальные причины утечки памяти и часто самый быстрый способ отладки.
Отслеживание выделения памяти также имеет существенное преимущество, позволяя делиться результатами без включения конфиденциальной информации, которая может содержаться в куче памяти.
Выявляйте утечки с помощью LeakCanary
LeakCanary — это мощный инструмент для выявления утечек памяти в приложениях Android. Чтобы узнать больше о том, как использовать LeakCanary в своем приложении, посетите сайт LeakCanary .
Как сообщать о проблемах с SDK Google
Если вы попробовали методы, описанные в этом документе, и подозреваете утечку памяти в наших SDK, свяжитесь со службой поддержки клиентов, предоставив как можно больше следующей информации:
Пошаговая инструкция по воспроизведению утечки памяти . Если для выполнения этих шагов требуется сложный код, может помочь скопировать код, воспроизводящий проблему, в наше тестовое приложение и указать дополнительные шаги, которые необходимо выполнить в пользовательском интерфейсе для запуска утечки.
Дампы памяти, полученные из вашего приложения, воспроизводят проблему . Сделайте снимки дампов памяти в два разных момента времени, которые показывают существенное увеличение использования памяти.
Если ожидается утечка памяти в нативном режиме , предоставьте данные отслеживания выделения памяти из heapprofd .
Отчет об ошибке, составленный после того, как вы воспроизвели ситуацию утечки памяти.
Трассировка стека любых сбоев, связанных с памятью .
Важное замечание : трассировки стека обычно недостаточно для отладки проблем с памятью, поэтому обязательно предоставьте также один из других видов информации.