LeakCanary — что это такое, библиотека для поиска утечек в Android

Автор: IT Sectr Опубликовано: 2026-03-30 Время чтения: 9 мин

LeakCanary — это библиотека с открытым исходным кодом от Square для автоматического обнаружения утечек памяти в Android-приложениях. Она интегрируется в процесс разработки и в реальном времени отслеживает жизненный цикл Activity, Fragment, ViewModel и других компонентов, сигнализируя об утечках сразу после их возникновения. По данным Square Open Source, библиотека используется в тысячах проектов и считается стандартом де-факто для диагностики памяти на Android.

Главное

  • LeakCanary — библиотека для автоматического обнаружения утечек памяти на Android.
  • Механизм работы основан на WeakReference и ручном запуске GC после уничтожения компонента.
  • Heap dump создаётся автоматически при обнаружении утечки и анализируется встроенным анализатором.
  • Результат — точная цепочка ссылок (leak trace), указывающая на место утечки в коде.
  • LeakCanary 2.x не требует ручной настройки — достаточно одной зависимости в build.gradle.

Что такое LeakCanary?

LeakCanary — это библиотека для автоматического обнаружения утечек памяти в Android-приложениях, разработанная компанией Square. Она встраивается в процесс сборки приложения и автоматически отслеживает, когда объекты, которые должны быть уничтожены (Activity, Fragment, View), остаются в памяти. При обнаружении утечки LeakCanary формирует heap dump и анализирует цепочку ссылок, удерживающих объект.

Библиотека стала стандартом в Android-сообществе: по данным GitHub, проект собрал более 28 тысяч звёзд и используется в приложениях Google, Uber, Airbnb и Facebook. LeakCanary доступен в двух основных версиях: классическая 1.x (с ручной настройкой) и современная 2.x (автоматическая интеграция через ContentProvider). Версия 2.x не требует изменения Application-класса — зависимости достаточно для полноценной работы.

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

Почему LeakCanary важен для Android-разработки

Утечки памяти на Android критичнее, чем на десктопе, из-за ограниченного объёма RAM на мобильных устройствах. Даже утечка в 5–10 МБ на каждом переходе между экранами может привести к OutOfMemoryError через 30–40 минут использования приложения. LeakCanary обнаруживает такие проблемы на стадии разработки, не дожидаясь падения на проде.

Как работает LeakCanary?

LeakCanary использует слабые ссылки (WeakReference) в комбинации с принудительным вызовом сборщика мусора. Когда Activity или Fragment вызывают onDestroy, LeakCanary создаёт WeakReference на этот объект и запускает GC через короткую задержку (по умолчанию 5 секунд). Если после GC объект всё ещё доступен через WeakReference, значит, он удерживается сильной ссылкой — фиксируется утечка.

После обнаружения утечки LeakCanary делает heap dump (дамп кучи) — полный снимок памяти приложения в формате HPROF. Далее встроенный анализатор (Shark для версии 2.x) строит граф достижимости от GC Roots до утёкшего объекта и находит кратчайший путь — цепочку ссылок, удерживающих объект в памяти.

kotlin
// Упрощённая логика детекции LeakCanary
class ObjectWatcher {
    private val watchedReferences = CopyOnWriteArrayList<KeyedWeakReference>()

    fun watch(watchedObject: Any, description: String) {
        val reference = KeyedWeakReference(watchedObject, description)
        watchedReferences.add(reference)
        BackgroundHandler.postDelayed({
            checkForLeaks()
        }, 5000)
    }

    private fun checkForLeaks() {
        GcTrigger.runGc() // принудительный GC
        for (ref in watchedReferences) {
            if (ref.get() != null) {
                onLeakFound(ref) // объект пережил GC — это утечка
            }
        }
    }
}

Ключевой момент — принудительный вызов GcTrigger.runGc(). Без него невозможно отличить объект, который реально утёк, от объекта, который GC ещё не успел собрать. LeakCanary делает это до трёх раз: если после трёх циклов GC объект всё ещё в памяти — утечка подтверждена.

Что такое Shark — анализатор heap dump

Shark — это встроенный в LeakCanary 2.x анализатор heap dump, написанный на Kotlin. В отличие от предыдущего анализатора HAHA, Shark не загружает весь HPROF-файл в память, а обходит его граф объектов с минимальными аллокациями. Это снижает потребление RAM при анализе с 50 MB до 2–5 MB и сокращает время анализа с 30 секунд до 1–3 секунд.

Как установить и настроить LeakCanary?

Установка LeakCanary 2.x в современный Android-проект занимает одну строку в build.gradle. Библиотека использует ContentProvider для автоматической инициализации — не нужно править Application-класс или добавлять какой-либо код в MainActivity. Подключение выполняется только для debug-сборки, чтобы в релизном APK не было лишнего кода.

groovy
// build.gradle (app/module)
dependencies {
    // debugImplementation — библиотека только для debug-сборки
    debugImplementation "com.squareup.leakcanary:leakcanary-android:2.14"
}

После добавления зависимости и пересборки проекта LeakCanary автоматически появляется в приложении. При первом запуске библиотека показывает системное уведомление об активации. Все обнаруженные утечки отображаются в виде уведомлений — нажатие на уведомление открывает экран с детальным отчётом (LeakTrace).

Для кастомизации можно создать собственный AppWatcherInstaller и переопределить параметры: таймаут ожидания GC, список отслеживаемых типов объектов, включение сохранения heap dump на диск. Однако для 90% проектов конфигурация по умолчанию является оптимальной.

Настройка для корутин и Jetpack Compose

Начиная с версии 2.12, LeakCanary поддерживает автоматическое отслеживание ViewModel, корутинных скоупов и State-объектов Compose. Дополнительных зависимостей не требуется — библиотека сама определяет, какие компоненты Jetpack используются в проекте, и активирует соответствующие детекторы.

Как читать отчёт LeakCanary

Отчёт LeakCanary (LeakTrace) — это многострочная цепочка ссылок от GC Root до утёкшего объекта. Каждая строка показывает класс и поле, через которое проходит сильная ссылка. Разработчику нужно читать цепочку снизу вверх: нижняя строка — утёкший объект, верхняя — точка входа (GC Root).

Типичный LeakTrace выглядит так: GC Root → статическое поле Application → синглтон → callback → Activity. Если разработчик видит такую цепочку, проблема ясна: синглтон держит callback, который захватил ссылку на Activity. Решение — заменить сильную ссылку на слабую в синглтоне.

text
┬
├─ android.app.Application
│    Leaking: NO (Application — singleton)
│    ↓ Application.leakedActivities
├─ java.util.ArrayList
│    Leaking: NO (ArrayList — normal)
│    ↓ ArrayList[0]
├─ com.example.MainActivity
│    Leaking: YES (Activity destroyed but still in memory)
│    ↓ MainActivity.mCallback
├─ com.example.CallbackWrapper
│    Leaking: UNKNOWN
│    ↓ CallbackWrapper.mListener
│              ~~~~~~~~~~
├─ com.example.MyCallback (anonymous)
│    Leaking: UNKNOWN
│    ↓ MyCallback.this$0
├─ com.example.MainActivity
│    Leaking: YES (MainActivity is the leak)
╰

В этом примере LeakCanary показывает, что MainActivity удерживается через цепочку: Application → ArrayList → MainActivity → CallbackWrapper → MyCallback → опять MainActivity. Стрелка this$0 указывает, что анонимный класс MyCallback захватил внешнюю ссылку на Activity. Решение — сделать колбэк слабой ссылкой или отменять его в onDestroy.

LeakCanary также показывает статус утечки для каждого элемента цепочки: NO (нет утечки — это корневой элемент), YES (объект должен быть уничтожен), UNKNOWN (не удалось определить статус). Статус UNKNOWN не означает проблемы — это промежуточный объект, который LeakCanary не может однозначно классифицировать.

LeakCanary 2.x против 1.x: ключевые отличия

Переход с версии 1.x на 2.x был кардинальным: разработчики переписали библиотеку с нуля, заменив устаревший HAHA-анализатор на собственный движок Shark, написанный на Kotlin. Shark работает на порядок быстрее, требует меньше памяти для анализа и точнее определяет корневые причины утечек.

ПараметрLeakCanary 1.xLeakCanary 2.x
Язык анализатораJava (HAHA — fork of Android SDK)Kotlin (Shark — собственный движок)
УстановкаРучная настройка AppWatcher в ApplicationАвтоматическая через ContentProvider
Скорость10–30 секунд на анализ heap dump1–5 секунд на анализ heap dump
ПроизводительностьЗанимает 10–50 MB RAM при анализеЗанимает 2–10 MB RAM при анализе

Ключевое преимущество Shark — он не загружает весь heap dump в память, а обходит его граф ссылок с минимальными аллокациями. Это делает LeakCanary 2.x пригодным для использования на устройствах с низким объёмом RAM без риска OutOfMemoryError при анализе.

В версии 2.x также появилась возможность экспорта heap dump в файл для последующего анализа в Android Studio Memory Profiler. Для этого нужно включить настройку dumpHeapWhenLeakFound в конфигурации AppWatcher.

Типичные утечки, которые находит LeakCanary

LeakCanary эффективно обнаруживает несколько классов утечек, характерных для Android. Наиболее часто встречается утечка через статические ссылки на Activity — разработчики сохраняют ссылку на контекст Activity в синглтоне, и Activity не может быть собран GC после завершения её жизненного цикла.

Вторая по частоте категория — утечки через незарегистрированные слушатели. Если в onStart был вызван registerListener, но в onStop/onDestroy не вызван unregisterListener — объект-слушатель удерживается системой даже после уничтожения активности. LeakCanary однозначно показывает, какой слушатель и в каком системном сервисе остался живым.

kotlin
// Типичная утечка: Activity захвачена в callback синглтона
object AnalyticsManager {
    private var callback: ((String) -> Unit)? = null

    fun register(callback: (String) -> Unit) {
        this.callback = callback // сильная ссылка на callback
    }

    fun unregister() {
        callback = null // НЕ ЗАБЫТЬ вызвать в onDestroy!
    }
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        AnalyticsManager.register { event ->
            logEvent(event) // лямбда захватывает this
        }
        // если не вызвать unregister в onDestroy → утечка Activity
    }
}

Третья категория — утечки через Fragment в BackStack. Если FragmentTransaction.addToBackStack() вызывается без удаления Fragment при возврате, старые экземпляры Fragment остаются в памяти. LeakCanary помогает обнаружить такие скрытые утечки на ранних этапах разработки.

Для каждой обнаруженной утечки LeakCanary предлагает описание и рекомендации по исправлению. В версии 2.14 добавлена интеграция с Android Lint — библиотека может автоматически создавать задачи в issue tracker при обнаружении утечки в CI.

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

Нужно ли удалять LeakCanary из релизного APK?

Да, обязательно. LeakCanary подключается через debugImplementation в build.gradle, что автоматически исключает его из релизной сборки. Если подключить через implementation, библиотека попадёт в релизный APK и будет показывать утечки конечным пользователям — это недопустимо.

Замедляет ли LeakCanary работу приложения?

Влияние на производительность минимально. LeakCanary активируется только после onDestroy компонента и не вмешивается в отрисовку UI или обработку касаний. Единственная затрата — короткая пауза принудительного GC (около 100 мс) и запись heap dump при утечке (сотые доли секунды).

Как экспортировать отчёт LeakCanary?

LeakCanary автоматически сохраняет heap dump в формате HPROF в папку приложения. Файл можно экспортировать через Android Studio: Device File Explorer → data/data/com.example/files/leakcanary/. Для просмотра откройте файл в Memory Profiler через Capture → Open Heap Dump.

Работает ли LeakCanary с Jetpack Compose?

Да, начиная с версии 2.12 LeakCanary полностью поддерживает Jetpack Compose. Библиотека отслеживает Composition-контексты и State-объекты, автоматически определяя утечки в Composable-функциях. Отдельная настройка не требуется — работает из коробки.

Может ли LeakCanary ошибаться (false positive)?

Ложные срабатывания возможны, но редки. LeakCanary использует тройной вызов GC перед объявлением утечки, что исключает большую часть false positive. Если вы считаете, что срабатывание ложное — создайте IgnoredReference для конкретного класса в конфигурации.

Итоги

  • LeakCanary — стандартная библиотека для автоматического обнаружения утечек памяти в Android-приложениях.
  • Библиотека использует WeakReference и принудительный GC для детекции объектов, переживших свой жизненный цикл.
  • Heap dump анализируется встроенным движком Shark, который строит цепочку ссылок от GC Root до утёкшего объекта.
  • Установка в современном проекте — одна строка в build.gradle: debugImplementation.
  • LeakCanary 2.x полностью переписан на Kotlin и работает в 5–10 раз быстрее предыдущей версии.
  • Наиболее частые утечки: статические ссылки на Activity, незарегистрированные слушатели и Fragment в BackStack.
  • Внедрите LeakCanary в debug-сборку каждого проекта — это предотвратит утечки на продакшене.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также