Получите снимок дампа кучи

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

На этой странице описаны инструменты Android Studio для сбора и анализа дампов кучи. Вы также можете проверить память приложения из командной строки с помощью dumpsys и посмотреть события сборки мусора в Logcat.

Зачем профилировать память приложения

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

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

Информацию о том, как снизить потребление памяти приложением, вы найдете в статье Управление памятью приложения.

Общие сведения о дампе кучи

Чтобы получить снимок дампа кучи, выберите задачу Analyze Memory Usage (Heap Dump) (Анализ использования памяти (дамп кучи)) (используйте Profiler: run 'app' as debuggable (complete data) (Профилировщик: запустить приложение как отладочное (полные данные))). При создании дампа кучи объем памяти Java может временно увеличиться. Это нормально, поскольку дамп кучи происходит в том же процессе, что и ваше приложение, и для сбора данных требуется некоторое количество памяти. После создания дампа кучи вы увидите следующее:

Просмотр дампа кучи в Профилировщике Android Studio.

В списке курсов указана следующая информация:

  • Выделения. Количество выделений в куче.
  • Размер нативного кода. Общий объем нативной памяти, используемой этим типом объектов (в байтах). Здесь вы увидите память для некоторых объектов, выделенных в Java, поскольку Android использует нативную память для некоторых классов фреймворка, например Bitmap.

  • Объем памяти, занимаемый объектом. Общий объем памяти Java, используемый этим типом объекта (в байтах).

  • Сохраненный размер. Общий объем памяти, занимаемый всеми экземплярами этого класса (в байтах).

Чтобы отфильтровать кучи, используйте меню:

  • Куча приложения (по умолчанию). Основная куча, в которой приложение выделяет память.
  • Куча изображений. Загрузочный образ системы, содержащий классы, которые предварительно загружаются во время загрузки. Распределения здесь никогда не перемещаются и не исчезают.
  • Куча Zygote. Куча с копированием при записи, из которой в системе Android создается процесс приложения.

В раскрывающемся меню выберите, как упорядочить распределения:

  • Упорядочить по курсу (по умолчанию). Все распределения группируются по названию курса.
  • Упорядочить по пакетам. Все распределения группируются по названию пакета.

Чтобы отфильтровать группы курсов, используйте раскрывающийся список:

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

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

  • Глубина. Наименьшее количество переходов от любого корня GC до выбранного экземпляра.
  • Native Size (Размер в нативной памяти). Размер экземпляра в нативной памяти. Этот столбец виден только для Android 7.0 и более поздних версий.
  • Объем памяти, занимаемый объектом. Объем памяти Java, занимаемый этим экземпляром.
  • Сохраненный размер. Объем памяти, который занимает этот экземпляр (согласно дереву доминаторов).

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

  • Поля. Все поля в этом экземпляре.
  • Ссылки. Показывает все ссылки на объект, выделенный на вкладке Экземпляр.
Представления Instances (Экземпляры), Fields (Поля) и References (Ссылки) в окне инструмента Heap Dump (Дамп кучи).

Обнаружение повторяющихся растровых изображений

Начиная с Android Studio Narwhal 4, вы также можете обнаруживать избыточные битовые карты в представлении дампа кучи.

Вот как их найти:

  1. Как открыть вкладку Profiler в Android Studio
  2. Нажмите Дамп кучи (или Анализ использования памяти), а затем – кнопку записи, чтобы сделать снимок текущего состояния памяти приложения.
  3. Проверьте результаты анализа на наличие желтого предупреждающего треугольника ⚠️, который Android Studio использует для пометки дубликатов растровых изображений, хранящихся несколько раз.
    • Вы также можете перейти к заголовку профилировщика, выбрать Filter by (Фильтровать по) и указать параметр Duplicate Bitmaps (Дублирующиеся растровые изображения).
  4. Нажмите на любую запись с пометкой, чтобы открыть панель Предварительный просмотр растрового изображения и увидеть, какое именно изображение является повторным нарушителем.
  5. Используйте это визуальное подтверждение, чтобы отследить избыточную логику загрузки в коде и реализовать более эффективную стратегию кеширования.
Найдите повторяющиеся битовые карты, помеченные желтым треугольником ⚠️.

Как найти утечки памяти

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

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

  • Долгоживущие ссылки на Activity или Context, которые могут привести к утечке графа композиции Compose (например, ComposeView и его дочерних composable-функций).
  • Утечка объектов состояния Jetpack Compose (MutableState), хранилищ состояния или лямбда-выражений, которые захватывают Context.
  • Забыли очистить прослушиватели или наблюдатели в блоке onDispose DisposableEffect.
  • Нестатические внутренние классы, такие как Runnable, которые могут содержать экземпляр Activity.
  • Кеши, в которых объекты хранятся дольше, чем необходимо.

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

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

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

Вы также можете вызвать утечку памяти одним из следующих способов:

  • Поверните устройство из вертикального положения в горизонтальное и обратно несколько раз, когда оно находится в разных состояниях. Поворот устройства часто может привести к утечке Activity (и, следовательно, размещенного в нем дерева Compose UI и связанных с ним деревьев состояний), если ваше приложение содержит ссылку на Activity или Context внутри асинхронных операций или хранилищ состояний.
  • Переключайтесь между своим и другими приложениями, когда они находятся в разных состояниях. Например, перейдите на главный экран, а затем вернитесь в приложение.

Как экспортировать и импортировать запись дампа кучи

Вы можете экспортировать и импортировать файл дампа кучи на вкладке Past Recordings (Предыдущие записи) в профилировщике. Android Studio сохраняет запись в виде файла .hprof.

Если вы хотите использовать другой анализатор файлов .hprof, например jhat, вам нужно преобразовать файл .hprof из формата Android в формат файла Java SE .hprof. Чтобы преобразовать формат файла, используйте инструмент hprof-conv, который находится в каталоге {android_sdk}/platform-tools/. Выполните команду hprof-conv с двумя аргументами: исходным названием файла .hprof и местом, где нужно сохранить преобразованный файл .hprof, включая его новое .hprof название. Пример:

hprof-conv heap-original.hprof heap-converted.hprof

Дополнительные ресурсы