Сделайте дамп кучи, чтобы узнать, какие объекты в приложении используют память в момент создания дампа, и выявить утечки памяти или особенности распределения памяти, которые приводят к задержкам, зависаниям и даже сбоям в работе приложения. Особенно полезно делать дампы кучи после длительного сеанса пользователя, когда в памяти могут оставаться объекты, которых там быть не должно.
На этой странице описаны инструменты Android Studio для сбора и анализа дампов кучи. Вы также можете проверить память приложения из командной строки с помощью dumpsys и посмотреть события сборки мусора в Logcat.
Зачем профилировать память приложения
В Android используется управляемая среда памяти. Когда система определяет, что приложение больше не использует некоторые объекты, сборщик мусора возвращает неиспользуемую память в кучу. Алгоритмы поиска неиспользуемой памяти постоянно совершенствуются, но в любой версии Android системе приходится ненадолго приостанавливать выполнение кода. В большинстве случаев паузы незаметны. Однако если приложение выделяет память быстрее, чем система может ее собрать, то в работе приложения могут возникать задержки, пока сборщик не освободит достаточно памяти для удовлетворения ваших запросов. Из-за этого приложение может пропускать кадры, что приводит к заметному замедлению работы.
Даже если приложение не работает медленно, утечка памяти может происходить, когда оно находится в фоновом режиме. Это может замедлить работу остальной памяти системы, вызывая ненужные события сборки мусора. В конечном итоге система будет вынуждена завершить процесс приложения, чтобы освободить память. Когда пользователь вернется в приложение, его процесс должен перезапуститься полностью.
Информацию о том, как снизить потребление памяти приложением, вы найдете в статье Управление памятью приложения.
Общие сведения о дампе кучи
Чтобы получить снимок дампа кучи, выберите задачу Analyze Memory Usage (Heap Dump) (Анализ использования памяти (дамп кучи)) (используйте Profiler: run 'app' as debuggable (complete data) (Профилировщик: запустить приложение как отладочное (полные данные))). При создании дампа кучи объем памяти Java может временно увеличиться. Это нормально, поскольку дамп кучи происходит в том же процессе, что и ваше приложение, и для сбора данных требуется некоторое количество памяти. После создания дампа кучи вы увидите следующее:
В списке курсов указана следующая информация:
- Выделения. Количество выделений в куче.
Размер нативного кода. Общий объем нативной памяти, используемой этим типом объектов (в байтах). Здесь вы увидите память для некоторых объектов, выделенных в Java, поскольку Android использует нативную память для некоторых классов фреймворка, например
Bitmap.Объем памяти, занимаемый объектом. Общий объем памяти Java, используемый этим типом объекта (в байтах).
Сохраненный размер. Общий объем памяти, занимаемый всеми экземплярами этого класса (в байтах).
Чтобы отфильтровать кучи, используйте меню:
- Куча приложения (по умолчанию). Основная куча, в которой приложение выделяет память.
- Куча изображений. Загрузочный образ системы, содержащий классы, которые предварительно загружаются во время загрузки. Распределения здесь никогда не перемещаются и не исчезают.
- Куча Zygote. Куча с копированием при записи, из которой в системе Android создается процесс приложения.
В раскрывающемся меню выберите, как упорядочить распределения:
- Упорядочить по курсу (по умолчанию). Все распределения группируются по названию курса.
- Упорядочить по пакетам. Все распределения группируются по названию пакета.
Чтобы отфильтровать группы курсов, используйте раскрывающийся список:
- Все классы (по умолчанию). Показывает все классы, включая классы из библиотек и зависимостей.
- Показать утечки в действиях/фрагментах. Показывает классы, которые вызывают утечки памяти.
- Показать классы проекта. Показывает только классы, определенные вашим проектом.
Нажмите на название класса, чтобы открыть панель Экземпляр. Для каждого экземпляра в списке указаны следующие сведения:
- Глубина. Наименьшее количество переходов от любого корня GC до выбранного экземпляра.
- Native Size (Размер в нативной памяти). Размер экземпляра в нативной памяти. Этот столбец виден только для Android 7.0 и более поздних версий.
- Объем памяти, занимаемый объектом. Объем памяти Java, занимаемый этим экземпляром.
- Сохраненный размер. Объем памяти, который занимает этот экземпляр (согласно дереву доминаторов).
Нажмите на экземпляр, чтобы посмотреть сведения о нем, включая поля и ссылки. Распространенные типы полей и ссылок – это структурированные типы
,
массивы
и примитивные типы данных
в Java. Нажмите правой кнопкой мыши на поле или ссылку, чтобы перейти к связанному экземпляру или строке в исходном коде.
- Поля. Все поля в этом экземпляре.
- Ссылки. Показывает все ссылки на объект, выделенный на вкладке Экземпляр.
Обнаружение повторяющихся растровых изображений
Начиная с Android Studio Narwhal 4, вы также можете обнаруживать избыточные битовые карты в представлении дампа кучи.
Вот как их найти:
- Как открыть вкладку Profiler в Android Studio
- Нажмите Дамп кучи (или Анализ использования памяти), а затем – кнопку записи, чтобы сделать снимок текущего состояния памяти приложения.
- Проверьте результаты анализа на наличие желтого предупреждающего треугольника ⚠️, который Android Studio использует для пометки дубликатов растровых изображений, хранящихся несколько раз.
- Вы также можете перейти к заголовку профилировщика, выбрать Filter by (Фильтровать по) и указать параметр Duplicate Bitmaps (Дублирующиеся растровые изображения).
- Нажмите на любую запись с пометкой, чтобы открыть панель Предварительный просмотр растрового изображения и увидеть, какое именно изображение является повторным нарушителем.
- Используйте это визуальное подтверждение, чтобы отследить избыточную логику загрузки в коде и реализовать более эффективную стратегию кеширования.
Как найти утечки памяти
Чтобы быстро отфильтровать классы, которые могут быть связаны с утечками памяти, откройте раскрывающийся список классов и выберите Показать утечки действий/фрагментов. Android Studio показывает классы, которые, по ее мнению, указывают на утечки памяти для экземпляров Activity и Fragment в вашем приложении.
Чтобы найти утечки памяти вручную, просмотрите списки классов и экземпляров и найдите объекты с большим сохраненным размером. Проверьте, не вызвана ли утечка памяти одной из следующих причин:
- Долгоживущие ссылки на
ActivityилиContext, которые могут привести к утечке графа композиции Compose (например,ComposeViewи его дочерних composable-функций). - Утечка объектов состояния Jetpack Compose (
MutableState), хранилищ состояния или лямбда-выражений, которые захватываютContext. - Забыли очистить прослушиватели или наблюдатели в блоке
onDisposeDisposableEffect. - Нестатические внутренние классы, такие как
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