Android

Оптимизация сборщика мусора в Android: руководство по настройке

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

Обновлено 6 апреля 2026 г.
10-15 мин
Средняя
FixPedia Team
Применимо к:Android 10–15 (API 29–35)Android Studio Iguana+Kotlin/Java приложенияУстройства с ART-рантаймом

Зачем разбираться в работе сборщика мусора

В современных версиях Android за управление оперативной памятью отвечает среда выполнения ART (Android Runtime). Сборщик мусора (Garbage Collector, GC) автоматически находит и удаляет объекты, которые больше не используются приложением. Пока этот процесс полностью автоматизирован, некорректная работа с памятью приводит к заметным «фризам» интерфейса (stop-the-world паузы) и вылетам с ошибкой OutOfMemoryError.

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

Требования и подготовка

Чтобы повторить описанные действия, подготовьте рабочее окружение:

  • Установленный Android Studio Iguana или новее с поддержкой Android SDK 34+.
  • Физическое устройство или эмулятор на базе Android 10 (API 29) или выше.
  • Включённые Параметры разработчика и активная отладка по USB.
  • Базовое понимание жизненного цикла Activity/Fragment и работы ссылок в Kotlin/Java.

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

Шаг 1: Включите профилирование памяти в Android Studio

Откройте ваш проект и перейдите в нижнюю панель IDE. Найдите вкладку Profiler. Если она скрыта, откройте её через View → Tool Windows → Profiler. Запустите приложение на подключённом устройстве и кликните на карточку процесса вашего приложения в списке активных процессов.

В открывшейся панели выберите раздел Memory. Нажмите кнопку Record (круглая кнопка с точкой), чтобы начать захват метрик. Выполните сценарий использования, который вызывает подозрения на утечку: быстро открывайте и закрывайте экраны, прокручивайте длинные списки или загружайте изображения. Остановите запись. Вы увидите график, где цветные зоны показывают моменты работы сборщика мусора.

Шаг 2: Сделайте дамп кучи и найдите «виновников» нагрузки

На том же графике Memory нажмите кнопку Dump Java Heap. Android Studio создаст снимок оперативной памяти в формате .hprof. В появившемся окне Captures выберите свежий дамп.

Переключитесь в режим Package Tree View или Class View. Отсортируйте список по колонке Retained Size. Объекты с наибольшим значением — это то, что удерживает память даже после вызова GC. Обратите внимание на:

  • Bitmap и Drawable объекты без оптимизации.
  • Коллекции (List, Map), которые постоянно растут без очистки.
  • Замыкания (lambdas) и Handler с неявными ссылками на контекст Activity.

Шаг 3: Примените оптимизации в коде

На основе анализа внесите правки в исходный код. Основные приёмы для снижения давления на сборщик мусора:

  1. Переиспользуйте тяжёлые объекты. Вместо постоянного создания новых ArrayList или Bitmap используйте объектные пулы или библиотеки вроде Glide/Coil, которые кэшируют изображения и управляют их жизненным циклом.
  2. Избегайте скрытых выделений в циклах. Конкатенация строк внутри for/while создаёт множество временных объектов. Замените оператор + на StringBuilder или используйте строковые шаблоны Kotlin.
  3. Очищайте ссылки при уничтожении компонентов. В onDestroy() или onCleared() (для ViewModel) обнуляйте слушатели, отменяйте корутины и отписывайтесь от Flow/LiveData.

Пример безопасной работы с данными:

// Плохо: создает новые списки и временные объекты при каждом вызове
fun processItems(items: List<String>): List<String> {
    return items.filter { it.isNotEmpty() }.map { it.trim() }
}

// Хорошо: переиспользует буфер и минимизирует выделение памяти
fun processItemsOptimized(items: List<String>, reusableList: MutableList<String>) {
    reusableList.clear()
    for (item in items) {
        if (item.isNotEmpty()) {
            reusableList.add(item.trim())
        }
    }
}

Шаг 4: Проверьте результат в реальных условиях

Пересоберите приложение в режиме Release или Profile. Артефакты debug-сборки содержат отладочный код и инструменты, которые искусственно увеличивают размер объектов и искажают поведение GC. Повторно запустите Profiler и выполните тот же сценарий, что и в первом шаге.

Сравните новые графики с предыдущими. Обратите внимание на:

  • Частоту срабатываний GC: она должна снизиться или сместиться в моменты простоя приложения.
  • Пиковое потребление кучи: график должен выглядеть более ровным, без резких «пил».
  • Время отклика интерфейса: используйте вкладку CPU Profiler или Frame Timing, чтобы убедиться, что кадры не выпадают из целевых 16 мс.

Проверка результата

Убедиться в эффективности проделанной работы можно двумя способами. Во-первых, выполните в терминале adb shell dumpsys meminfo <ваш.пакет> и сравните значения TOTAL PSS и Native Heap до и после изменений. Во-вторых, проверьте логи устройства на наличие сообщений вида GC_CONCURRENT или GC_FOR_ALLOC — их количество в минуту должно стремиться к нулю при обычном использовании.

Возможные проблемы

Даже при следовании инструкции могут возникнуть технические нюансы:

  • Дамп кучи занимает слишком много места. Android Studio предложит загрузить дамп на сервер или использовать потоковый анализатор. Для локального анализа увеличьте лимит памяти IDE в studio64.exe.vmoptions (флаг -Xmx4g) или ограничьте захват конкретным пакетом.
  • GC запускается слишком часто после оптимизаций. Это признак фрагментации кучи или нехватки нативной памяти. Перенесите тяжёлые вычисления в RenderScript/C++ через JNI или используйте android:largeHeap="true" в манифесте только для специфичных задач.
  • Профилировщик не показывает данные на Android 14+. Начиная с Android 13, Google ужесточил доступ к /data/local/tmp. Убедитесь, что вы подписываете APK отладочным ключом и запускаете приложение в режиме debuggable=true, иначе Profiler не сможет подключиться к рантайму.

⚠️ Важно: Не пытайтесь форсировать вызов сборщика мусора через System.gc(). В ART это лишь рекомендация, а в продакшн-сборках вызов часто игнорируется. Ручная сборка может вызвать лишние остановки потока и ухудшить отзывчивость интерфейса.

Часто задаваемые вопросы

Влияет ли ручная очистка кэша на работу сборщика мусора Android?
Почему приложение вылетает с ошибкой OutOfMemoryError, если GC работает автоматически?
Можно ли отключить Garbage Collector для повышения производительности?

Полезное

Включите профилирование памяти
Создайте дамп кучи (Heap Dump)
Оптимизируйте выделение памяти в коде
Проверьте результат после сборки Release