LeakCanary — är ett bibliotek med öppen källkod från Square för automatisk upptäckt av minnesläckor i Android-applikationer. Det integreras i utvecklingsprocessen och övervakar i realtid livscykeln för Activity, Fragment, ViewModel och andra komponenter, och signalerar läckor omedelbart efter att de uppstår. Enligt uppgifter från Square Open Source används biblioteket i tusentals projekt och anses vara de facto-standard för minnesdiagnostik på Android.
Huvudpunkter
LeakCanary — är ett bibliotek för automatisk upptäckt av minnesläckor i Android-applikationer, utvecklat av Square. Det är inbäddat i applikationens byggprocess och övervakar automatiskt när objekt som borde förstöras (Activity, Fragment, View) finns kvar i minnet. Vid upptäckt av en läcka skapar LeakCanary en heap dump och analyserar referenskedjan som håller objektet.
Biblioteket har blivit en standard i Android-gemenskapen: enligt GitHub-data har projektet samlat över 28 tusen stjärnor och används i applikationer från Google, Uber, Airbnb och Facebook. LeakCanary finns i två huvudversioner: klassisk 1.x (med manuell konfiguration) och modern 2.x (automatisk integration via ContentProvider). Version 2.x kräver ingen ändring av Application-klassen — ett beroende räcker för full funktion.
LeakCanarys huvuduppgift är att upptäcka situationer där ett objekt fortsätter att finnas i minnet efter att dess livscykel har avslutats. Detta är typiskt för läckor via statiska fält, singlar, oregistrerade callbacks, anonyma klasser och slutningar som fångar externa objekt.
Minnesläckor på Android är mer kritiska än på skrivbordet på grund av den begränsade mängden RAM på mobila enheter. Även en läcka på 5–10 MB vid varje skärmväxling kan leda till OutOfMemoryError efter 30–40 minuters användning av applikationen. LeakCanary upptäcker sådana problem i utvecklingsfasen, utan att vänta på en krasch i produktion.
LeakCanary använder svaga referenser (WeakReference) i kombination med tvångsanrop av garbage collectorn. När Activity eller Fragment anropar onDestroy skapar LeakCanary en WeakReference till detta objekt och startar GC efter en kort fördröjning (standard 5 sekunder). Om objektet efter GC fortfarande är tillgängligt via WeakReference betyder det att det hålls av en stark referens — en läcka registreras.
Efter upptäckt av en läcka gör LeakCanary en heap dump (fullständig ögonblicksbild av applikationens minne i HPROF-format). Därefter bygger den inbyggda analysatorn (Shark för version 2.x) en tillgänglighetsgraf från GC Roots till det läckta objektet och hittar den kortaste vägen — referenskedjan som håller objektet i minnet.
// Förenklad detektionslogik för 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() // tvångs-GC
for (ref in watchedReferences) {
if (ref.get() != null) {
onLeakFound(ref) // objektet överlevde GC — detta är en läcka
}
}
}
}
Nyckelpunkten — tvångsanropet av GcTrigger.runGc(). Utan det är det omöjligt att skilja ett objekt som faktiskt läckt från ett objekt som GC ännu inte hunnit samla in. LeakCanary gör detta upp till tre gånger: om objektet fortfarande finns i minnet efter tre GC-cykler — bekräftas läckan.
Shark — är den inbyggda heap dump-analysatorn i LeakCanary 2.x, skriven i Kotlin. Till skillnad från den tidigare analysatorn HAHA laddar Shark inte hela HPROF-filen i minnet, utan går igenom dess objektgraf med minimala allokeringar. Detta minskar RAM-förbrukningen under analys från 50 MB till 2–5 MB och förkortar analystiden från 30 sekunder till 1–3 sekunder.
Installation av LeakCanary 2.x i ett modernt Android-projekt tar en rad i build.gradle. Biblioteket använder ContentProvider för automatisk initiering — du behöver inte ändra Application-klassen eller lägga till kod i MainActivity. Anslutningen görs endast för debug-build, så att det inte finns överflödig kod i release-APK:n.
// build.gradle (app/module)
dependencies {
// debugImplementation — bibliotek endast för debug-build
debugImplementation "com.squareup.leakcanary:leakcanary-android:2.14"
}
Efter att ha lagt till beroendet och byggt om projektet visas LeakCanary automatiskt i applikationen. Vid första starten visar biblioteket en systemnotis om aktivering. Alla upptäckta läckor visas som notiser — klicka på notisen öppnar skärmen med den detaljerade rapporten (LeakTrace).
För anpassning kan du skapa din egen AppWatcherInstaller och åsidosätta parametrar: GC-timeout, lista över övervakade objekttyper, aktivering av att spara heap dump på disk. För 90% av projekten är standardkonfigurationen dock optimal.
Från och med version 2.12 stöder LeakCanary automatisk spårning av ViewModel, korutinomfång och State-objekt i Compose. Inga ytterligare beroenden krävs — biblioteket upptäcker själv vilka Jetpack-komponenter som används i projektet och aktiverar motsvarande detektorer.
LeakCanary-rapporten (LeakTrace) — är en flerradig referenskedja från GC Root till det läckta objektet. Varje rad visar klassen och fältet genom vilket den starka referensen passerar. Utvecklaren bör läsa kedjan nedifrån och upp: nedre raden — läckt objekt, övre raden — ingångspunkt (GC Root).
En typisk LeakTrace ser ut så här: GC Root → statiskt Application-fält → singleton → callback → Activity. Om en utvecklare ser en sådan kedja är problemet tydligt: singellet håller en callback som fångat en referens till Activity. Lösning — ersätt den starka referensen med en svag i singleton.
┬
├─ 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)
╰
I detta exempel visar LeakCanary att MainActivity hålls via kedjan: Application → ArrayList → MainActivity → CallbackWrapper → MyCallback → tillbaka till MainActivity. Pilen this$0 indikerar att den anonyma klassen MyCallback fångat en extern referens till Activity. Lösning — gör callbacken till en svag referens eller avbryt den i onDestroy.
LeakCanary visar också läckstatus för varje element i kedjan: NO (ingen läcka — detta är rotelementet), YES (objektet bör förstöras), UNKNOWN (status kunde inte fastställas). Status UNKNOWN betyder inget problem — det är ett mellanliggande objekt som LeakCanary inte entydigt kan klassificera.
Övergången från version 1.x till 2.x var genomgripande: utvecklarna skrev om biblioteket från grunden och ersatte den föråldrade HAHA-analysatorn med en egen motor Shark skriven i Kotlin. Shark arbetar avsevärt snabbare, kräver mindre minne för analys och bestämmer mer exakt grundorsakerna till läckor.
| Parameter | LeakCanary 1.x | LeakCanary 2.x |
|---|---|---|
| Analysatorspråk | Java (HAHA — fork av Android SDK) | Kotlin (Shark — egen motor) |
| Installation | Manuell konfiguration av AppWatcher i Application | Automatisk via ContentProvider |
| Hastighet | 10–30 sekunder för heap dump-analys | 1–5 sekunder för heap dump-analys |
| Prestanda | Tar 10–50 MB RAM under analys | Tar 2–10 MB RAM under analys |
Den viktigaste fördelen med Shark — den laddar inte hela heap dump i minnet, utan går igenom dess referensgraf med minimala allokeringar. Detta gör LeakCanary 2.x lämpligt för användning på enheter med låg RAM utan risk för OutOfMemoryError under analys.
I version 2.x har även möjligheten att exportera heap dump till en fil för senare analys i Android Studio Memory Profiler lagts till. För detta måste du aktivera inställningen dumpHeapWhenLeakFound i AppWatcher-konfigurationen.
LeakCanary upptäcker effektivt flera klasser av läckor som är karakteristiska för Android. Mest förekommande är läckor via statiska referenser till Activity — utvecklare lagrar en referens till Activity-kontexten i en singleton, och Activity kan inte samlas in av GC efter att dess livscykel har avslutats.
Den näst vanligaste kategorin — läckor via oregistrerade lyssnare. Om registerListener anropades i onStart men unregisterListener inte anropades i onStop/onDestroy — hålls lyssnarobjektet av systemet även efter att aktiviteten förstörts. LeakCanary visar otvetydigt vilken lyssnare och i vilken systemtjänst som förblivit aktiv.
// Typisk läcka: Activity fångad i en callbacks från singleton
object AnalyticsManager {
private var callback: ((String) -> Unit)? = null
fun register(callback: (String) -> Unit) {
this.callback = callback // stark referens till callback
}
fun unregister() {
callback = null // GLÖM INTE att anropa i onDestroy!
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
AnalyticsManager.register { event ->
logEvent(event) // lambda fångar this
}
// om du inte anropar unregister i onDestroy → Activity-läcka
}
}
Den tredje kategorin — läckor via Fragment i BackStack. Om FragmentTransaction.addToBackStack() anropas utan att Fragment tas bort vid återgång, stannar gamla Fragment-instanser kvar i minnet. LeakCanary hjälper till att upptäcka sådana dolda läckor i tidiga skeden av utvecklingen.
För varje upptäckt läcka erbjuder LeakCanary en beskrivning och rekommendationer för åtgärd. I version 2.14 har integration med Android Lint lagts till — biblioteket kan automatiskt skapa uppgifter i issue tracker när en läcka upptäcks i CI.
Vanliga frågor
Ja, absolut. LeakCanary ansluts via debugImplementation i build.gradle, vilket automatiskt utesluter det från release-bygget. Om du ansluter det via implementation kommer biblioteket in i release-APK:n och kommer att visa läckor för slutanvändare — detta är oacceptabelt.
Påverkan på prestandan är minimal. LeakCanary aktiveras endast efter komponentens onDestroy och stör inte UI-rendering eller touch-hantering. Den enda kostnaden — en kort paus för tvångs-GC (cirka 100 ms) och skrivning av heap dump vid läcka (hundradelar av en sekund).
LeakCanary sparar automatiskt heap dump i HPROF-format i applikationsmappen. Filen kan exporteras via Android Studio: Device File Explorer → data/data/com.example/files/leakcanary/. För att visa, öppna filen i Memory Profiler via Capture → Open Heap Dump.
Ja, från och med version 2.12 stöder LeakCanary helt Jetpack Compose. Biblioteket spårar Composition-kontexter och State-objekt och upptäcker automatiskt läckor i Composable-funktioner. Ingen separat konfiguration krävs — fungerar direkt.
Falska positiva utslag är möjliga men sällsynta. LeakCanary använder tre GC-anrop innan en läcka deklareras, vilket eliminerar de flesta falska positiva resultat. Om du tror att ett utslag är falskt — skapa en IgnoredReference för den specifika klassen i konfigurationen.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också