LeakCanary — je open source knihovna od Square pro automatickou detekci úniků paměti v Android aplikacích. Integruje se do vývojového procesu a v reálném čase sleduje životní cyklus Activity, Fragment, ViewModel a dalších komponent, signalizuje úniky ihned po jejich vzniku. Podle údajů Square Open Source je knihovna používána v tisících projektů a je považována za de facto standard pro diagnostiku paměti na Androidu.
Hlavní body
LeakCanary — je knihovna pro automatickou detekci úniků paměti v Android aplikacích, vyvinutá společností Square. Je vložena do procesu sestavování aplikace a automaticky sleduje, když objekty, které by měly být zničeny (Activity, Fragment, View), zůstávají v paměti. Při detekci úniku LeakCanary vytvoří heap dump a analyzuje řetězec referencí držících objekt.
Knihovna se stala standardem v komunitě Android: podle údajů GitHub projekt nasbíral přes 28 tisíc hvězdiček a je používán v aplikacích Google, Uber, Airbnb a Facebook. LeakCanary je k dispozici ve dvou hlavních verzích: klasická 1.x (s ruční konfigurací) a moderní 2.x (automatická integrace přes ContentProvider). Verze 2.x nevyžaduje úpravu třídy Application — jedna závislost stačí k plnému fungování.
Hlavním úkolem LeakCanary je detekovat situaci, kdy objekt nadále existuje v paměti poté, co jeho životní cyklus skončil. To je typické pro úniky přes statická pole, singly, neregistrovaná callbacky, anonymní třídy a uzávěry zachycující externí objekty.
Úniky paměti na Androidu jsou kritičtější než na desktopu kvůli omezenému množství RAM na mobilních zařízeních. I únik 5–10 MB při každém přepnutí obrazovky může vést k OutOfMemoryError po 30–40 minutách používání aplikace. LeakCanary detekuje takové problémy ve fázi vývoje, aniž by čekal na pád v produkci.
LeakCanary používá slabé reference (WeakReference) v kombinaci s vynuceným voláním garbage collectoru. Když Activity nebo Fragment zavolá onDestroy, LeakCanary vytvoří WeakReference na tento objekt a spustí GC po krátkém zpoždění (výchozí 5 sekund). Pokud je objekt po GC stále dostupný přes WeakReference, znamená to, že je držen silnou referencí — je zaznamenán únik.
Po detekci úniku LeakCanary provede heap dump (kompletní snímek paměti aplikace ve formátu HPROF). Následně vestavěný analyzátor (Shark pro verzi 2.x) vytvoří graf dosažitelnosti od GC Roots k uniklému objektu a najde nejkratší cestu — řetězec referencí držících objekt v paměti.
// Zjednodušená logika detekce 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() // vynucené GC
for (ref in watchedReferences) {
if (ref.get() != null) {
onLeakFound(ref) // objekt přežil GC — to je únik
}
}
}
}
Klíčovým momentem je vynucené volání GcTrigger.runGc(). Bez něj nelze rozlišit objekt, který skutečně unikl, od objektu, který GC ještě nestihl sesbírat. LeakCanary to dělá až třikrát: pokud je po třech GC cyklech objekt stále v paměti — únik je potvrzen.
Shark — je vestavěný analyzátor heap dump v LeakCanary 2.x, napsaný v Kotlinu. Na rozdíl od předchozího analyzátoru HAHA, Shark nenačítá celý HPROF soubor do paměti, ale prochází jeho graf objektů s minimálními alokacemi. To snižuje spotřebu RAM během analýzy z 50 MB na 2–5 MB a zkracuje dobu analýzy z 30 sekund na 1–3 sekundy.
Instalace LeakCanary 2.x do moderního Android projektu zabere jeden řádek v build.gradle. Knihovna používá ContentProvider pro automatickou inicializaci — není třeba upravovat třídu Application ani přidávat kód do MainActivity. Připojení se provádí pouze pro debug-build, aby v release APK nebyl zbytečný kód.
// build.gradle (app/module)
dependencies {
// debugImplementation — knihovna pouze pro debug-build
debugImplementation "com.squareup.leakcanary:leakcanary-android:2.14"
}
Po přidání závislosti a přestavění projektu se LeakCanary automaticky objeví v aplikaci. Při prvním spuštění knihovna zobrazí systémové oznámení o aktivaci. Všechny detekované úniky se zobrazují jako oznámení — kliknutí na oznámení otevře obrazovku s podrobnou zprávou (LeakTrace).
Pro přizpůsobení můžete vytvořit vlastní AppWatcherInstaller a přepsat parametry: časový limit čekání na GC, seznam sledovaných typů objektů, povolení ukládání heap dump na disk. Pro 90 % projektů je však výchozí konfigurace optimální.
Počínaje verzí 2.12 LeakCanary podporuje automatické sledování ViewModel, korutinových scopeů a State objektů Compose. Nejsou vyžadovány žádné další závislosti — knihovna sama zjistí, které Jetpack komponenty se v projektu používají, a aktivuje odpovídající detektory.
Zpráva LeakCanary (LeakTrace) — je víceřádkový řetězec referencí od GC Root k uniklému objektu. Každý řádek ukazuje třídu a pole, přes které prochází silná reference. Vývojář by měl číst řetězec zdola nahoru: spodní řádek — uniklý objekt, horní řádek — vstupní bod (GC Root).
Typický LeakTrace vypadá takto: GC Root → statické pole Application → singleton → callback → Activity. Pokud vývojář vidí takový řetězec, problém je jasný: singleton drží callback, který zachytil referenci na Activity. Řešení — nahradit silnou referenci slabou v singletonu.
┬
├─ 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)
╰
V tomto příkladu LeakCanary ukazuje, že MainActivity je držen přes řetězec: Application → ArrayList → MainActivity → CallbackWrapper → MyCallback → zpět MainActivity. Šipka this$0 ukazuje, že anonymní třída MyCallback zachytila externí referenci na Activity. Řešení — udělat callback slabou referencí nebo jej zrušit v onDestroy.
LeakCanary také zobrazuje stav úniku pro každý prvek řetězce: NO (žádný únik — toto je kořenový prvek), YES (objekt by měl být zničen), UNKNOWN (stav se nepodařilo určit). Status UNKNOWN neznamená problém — jde o mezilehlý objekt, který LeakCanary nelze jednoznačně klasifikovat.
Přechod z verze 1.x na 2.x byl radikální: vývojáři přepsali knihovnu od základů, nahradili zastaralý analyzátor HAHA vlastním motorem Shark napsaným v Kotlinu. Shark pracuje řádově rychleji, vyžaduje méně paměti pro analýzu a přesněji určuje hlavní příčiny úniků.
| Parametr | LeakCanary 1.x | LeakCanary 2.x |
|---|---|---|
| Jazyk analyzátoru | Java (HAHA — fork Android SDK) | Kotlin (Shark — vlastní motor) |
| Instalace | Ruční konfigurace AppWatcher v Application | Automatická přes ContentProvider |
| Rychlost | 10–30 sekund na analýzu heap dump | 1–5 sekund na analýzu heap dump |
| Výkon | Zabírá 10–50 MB RAM při analýze | Zabírá 2–10 MB RAM při analýze |
Klíčovou výhodou Shark je, že nenačítá celý heap dump do paměti, ale prochází jeho referenční graf s minimálními alokacemi. To činí LeakCanary 2.x vhodným pro použití na zařízeních s nízkou RAM bez rizika OutOfMemoryError při analýze.
Ve verzi 2.x se také objevila možnost exportu heap dump do souboru pro pozdější analýzu v Android Studio Memory Profiler. K tomu je třeba povolit nastavení dumpHeapWhenLeakFound v konfiguraci AppWatcher.
LeakCanary efektivně detekuje několik tříd úniků typických pro Android. Nejčastěji se vyskytuje únik přes statické reference na Activity — vývojáři ukládají referenci na kontext Activity v singletonu a Activity nemůže být sesbírána GC po dokončení svého životního cyklu.
Druhou nejčastější kategorií jsou úniky přes neregistrované posluchače. Pokud byl v onStart zavolán registerListener, ale v onStop/onDestroy nebyl zavolán unregisterListener — objekt-posluchač je držen systémem i po zničení aktivity. LeakCanary jednoznačně ukazuje, který posluchač a v které systémové službě zůstal aktivní.
// Typický únik: Activity zachycena v callbacku singletonu
object AnalyticsManager {
private var callback: ((String) -> Unit)? = null
fun register(callback: (String) -> Unit) {
this.callback = callback // silná reference na callback
}
fun unregister() {
callback = null // NEZAPOMEŇTE zavolat v onDestroy!
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
AnalyticsManager.register { event ->
logEvent(event) // lambda zachycuje this
}
// pokud nezavoláte unregister v onDestroy → únik Activity
}
}
Třetí kategorií jsou úniky přes Fragment v BackStack. Pokud je FragmentTransaction.addToBackStack() voláno bez odstranění Fragmentu při návratu, staré instance Fragmentu zůstávají v paměti. LeakCanary pomáhá odhalit takové skryté úniky v raných fázích vývoje.
Pro každý detekovaný únik LeakCanary nabízí popis a doporučení pro opravu. Ve verzi 2.14 byla přidána integrace s Android Lint — knihovna může automaticky vytvářet úkoly v issue tracker při detekci úniku v CI.
Často kladené otázky
Ano, rozhodně. LeakCanary se připojuje přes debugImplementation v build.gradle, což jej automaticky vylučuje z release sestavení. Pokud jej připojíte přes implementation, knihovna se dostane do release APK a bude zobrazovat úniky koncovým uživatelům — to je nepřijatelné.
Dopad na výkon je minimální. LeakCanary se aktivuje až po onDestroy komponenty a nezasahuje do vykreslování UI ani zpracování dotyků. Jediným nákladem je krátká pauza vynuceného GC (asi 100 ms) a zápis heap dump při úniku (setiny sekundy).
LeakCanary automaticky ukládá heap dump ve formátu HPROF do složky aplikace. Soubor lze exportovat přes Android Studio: Device File Explorer → data/data/com.example/files/leakcanary/. Pro zobrazení otevřete soubor v Memory Profiler přes Capture → Open Heap Dump.
Ano, od verze 2.12 LeakCanary plně podporuje Jetpack Compose. Knihovna sleduje kontexty Composition a State objekty, automaticky detekuje úniky v Composable funkcích. Samostatná konfigurace není nutná — funguje ihned.
Falešné aktivace jsou možné, ale vzácné. LeakCanary používá trojité volání GC před prohlášením úniku, což eliminuje většinu falešně pozitivních výsledků. Pokud se domníváte, že aktivace je falešná — vytvořte IgnoredReference pro konkrétní třídu v konfiguraci.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také