LeakCanary — mi ez, könyvtár a szivárgások kereséséhez Androidban

Szerző: IT Sectr Megjelenés: 2026-03-30 Olvasási idő: 9 perc

LeakCanary — egy nyílt forráskódú könyvtár a Square-től az Android-alkalmazások memóriaszivárgásainak automatikus észlelésére. Beépül a fejlesztési folyamatba, és valós időben követi az Activity, Fragment, ViewModel és más komponensek életciklusát, jelezve a szivárgásokat azok előfordulása után azonnal. A Square Open Source adatai szerint a könyvtárat több ezer projektben használják, és ez a de facto szabvány a memóriadiagnosztikában Androidon.

Főbb pontok

  • LeakCanary — könyvtár a memóriaszivárgások automatikus észlelésére Androidon.
  • Működési mechanizmus a WeakReference-en és a GC kézi elindításán alapul a komponens megsemmisítése után.
  • Heap dump automatikusan létrejön a szivárgás észlelésekor, és a beépített elemző elemzi.
  • Eredmény — pontos referencialánc (leak trace), amely a szivárgás helyét mutatja a kódban.
  • LeakCanary 2.x nem igényel kézi beállítást — egyetlen függőség a build.gradle-ben elegendő.

Mi az a LeakCanary?

LeakCanary — egy könyvtár a memóriaszivárgások automatikus észlelésére Android-alkalmazásokban, amelyet a Square fejlesztett. Beépül az alkalmazás építési folyamatába, és automatikusan figyeli, hogy a megsemmisítendő objektumok (Activity, Fragment, View) a memóriában maradnak-e. Szivárgás észlelésekor a LeakCanary heap dump-ot készít, és elemzi az objektumot tartó referencialáncot.

A könyvtár szabvánnyá vált az Android közösségben: a GitHub adatai szerint a projekt több mint 28 ezer csillagot gyűjtött, és használják a Google, Uber, Airbnb és Facebook alkalmazásai. A LeakCanary két fő verzióban érhető el: klasszikus 1.x (kézi beállítással) és modern 2.x (automatikus integráció ContentProvider-en keresztül). A 2.x verzió nem igényli az Application osztály módosítását — egy függőség elegendő a teljes működéshez.

A LeakCanary fő feladata annak a helyzetnek az észlelése, amikor egy objektum az életciklusának befejeződése után is a memóriában marad. Ez jellemző a statikus mezőkön, singletonokon, nem regisztrált callbackeken, névtelen osztályokon és a külső objektumokat befogó zárványokon keresztüli szivárgásokra.

Miért fontos a LeakCanary az Android-fejlesztésben

A memóriaszivárgások Androidon kritikusabbak, mint asztali gépen a mobil eszközök korlátozott RAM-ja miatt. Még egy 5–10 MB-os szivárgás is minden képernyőváltáskor OutOfMemoryError-hoz vezethet 30–40 perc használat után. A LeakCanary az ilyen problémákat a fejlesztési fázisban észleli, nem várva a termelésbeli összeomlásra.

Hogyan működik a LeakCanary?

LeakCanary gyenge referenciákat (WeakReference) használ a szemétgyűjtő kényszerített meghívásával kombinálva. Amikor az Activity vagy Fragment meghívja az onDestroy-t, a LeakCanary létrehoz egy WeakReference-t erre az objektumra, és rövid késleltetés után (alapértelmezetten 5 másodperc) elindítja a GC-t. Ha a GC után az objektum még mindig elérhető a WeakReference-en keresztül, akkor egy erős referencia tartja — szivárgás kerül rögzítésre.

A szivárgás észlelése után a LeakCanary heap dump-ot (az alkalmazás memóriájának teljes pillanatképét HPROF formátumban) készít. Ezután a beépített elemző (Shark a 2.x verzióhoz) elérhetőségi gráfot épít a GC Roots-tól a kiszivárgott objektumig, és megtalálja a legrövidebb utat — az objektumot a memóriában tartó referencialáncot.

kotlin
// A LeakCanary észlelési logikájának egyszerűsített változata
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() // kényszerített GC
        for (ref in watchedReferences) {
            if (ref.get() != null) {
                onLeakFound(ref) // az objektum túlélte a GC-t — ez szivárgás
            }
        }
    }
}

A kulcspont — a GcTrigger.runGc() kényszerített meghívása. Enélkül lehetetlen megkülönböztetni egy ténylegesen kiszivárgott objektumot attól, amelyet a GC még nem gyűjtött be. A LeakCanary ezt háromszor teszi meg: ha három GC-ciklus után az objektum még mindig a memóriában van — a szivárgás megerősítést nyer.

Mi az a Shark — heap dump elemző

Shark — a LeakCanary 2.x-be épített heap dump elemző, amely Kotlin nyelven íródott. Az előző HAHA elemzővel ellentétben a Shark nem tölti be a teljes HPROF fájlt a memóriába, hanem minimális foglalásokkal járja be az objektumgráfját. Ez csökkenti a RAM-fogyasztást elemzés közben 50 MB-ról 2–5 MB-ra, és lerövidíti az elemzési időt 30 másodpercről 1–3 másodpercre.

Hogyan telepítsük és konfiguráljuk a LeakCanary-t?

A LeakCanary 2.x telepítése egy modern Android projektben egy sort vesz igénybe a build.gradle-ben. A könyvtár a ContentProvider-t használja az automatikus inicializáláshoz — nem kell módosítani az Application osztályt vagy kódot hozzáadni a MainActivity-hez. A csatlakozás csak debug-build esetén történik, hogy a release APK-ban ne legyen felesleges kód.

groovy
// build.gradle (app/module)
dependencies {
    // debugImplementation — könyvtár csak debug-build-hez
    debugImplementation "com.squareup.leakcanary:leakcanary-android:2.14"
}

A függőség hozzáadása és a projekt újraépítése után a LeakCanary automatikusan megjelenik az alkalmazásban. Az első indításkor a könyvtár rendszerértesítést jelenít meg az aktiválásról. Az összes észlelt szivárgás értesítésként jelenik meg — az értesítésre kattintva megnyílik a részletes jelentés (LeakTrace) képernyője.

Testreszabáshoz létrehozhatja saját AppWatcherInstaller-jét, és felülírhatja a paramétereket: GC várakozási időtúllépés, a követett objektumtípusok listája, a heap dump lemezre mentésének engedélyezése. A projektek 90%-ánál azonban az alapértelmezett konfiguráció az optimális.

Konfiguráció korutinokhoz és Jetpack Compose-hoz

A 2.12-es verziótól kezdve a LeakCanary támogatja a ViewModel, a korutinszkópok és a Compose State objektumainak automatikus követését. Nincs szükség további függőségekre — a könyvtár maga érzékeli, hogy mely Jetpack-komponensek vannak használatban a projektben, és aktiválja a megfelelő detektorokat.

Hogyan olvassuk a LeakCanary jelentést

A LeakCanary jelentés (LeakTrace) — egy többsoros referencialánc a GC Root-tól a kiszivárgott objektumig. Minden sor azt az osztályt és mezőt mutatja, amelyen keresztül az erős referencia halad. A fejlesztőnek alulról felfelé kell olvasnia a láncot: alsó sor — kiszivárgott objektum, felső sor — belépési pont (GC Root).

Egy tipikus LeakTrace így néz ki: GC Root → statikus Application mező → singleton → callback → Activity. Ha a fejlesztő ilyen láncot lát, a probléma világos: a singleton tart egy callback-et, amely befogott egy referenciát az Activity-re. Megoldás — az erős referencia cseréje gyengére a singletonban.

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)
╰

Ebben a példában a LeakCanary azt mutatja, hogy a MainActivity-t a lánc tartja: Application → ArrayList → MainActivity → CallbackWrapper → MyCallback → vissza MainActivity. A this$0 nyíl jelzi, hogy a névtelen MyCallback osztály befogott egy külső referenciát az Activity-re. Megoldás — tegye a callback-et gyenge referenciává, vagy vonja vissza onDestroy-ben.

A LeakCanary a lánc minden elemére mutatja a szivárgás állapotát is: NO (nincs szivárgás — ez a gyökérelem), YES (az objektumot meg kell semmisíteni), UNKNOWN (az állapot nem határozható meg). Az UNKNOWN állapot nem jelent problémát — ez egy köztes objektum, amelyet a LeakCanary nem tud egyértelműen besorolni.

LeakCanary 2.x vs 1.x: főbb különbségek

Az 1.x verzióról a 2.x-re való áttérés radikális volt: a fejlesztők a nulláról írták újra a könyvtárat, lecserélve az elavult HAHA elemzőt a saját Shark motorra, amely Kotlin nyelven íródott. A Shark nagyságrenddel gyorsabban működik, kevesebb memóriát igényel az elemzéshez, és pontosabban határozza meg a szivárgások kiváltó okait.

ParaméterLeakCanary 1.xLeakCanary 2.x
Elemző nyelveJava (HAHA — az Android SDK fork-ja)Kotlin (Shark — saját motor)
TelepítésAppWatcher kézi konfigurálása az Application-benAutomatikus ContentProvider-en keresztül
Sebesség10–30 másodperc a heap dump elemzéséhez1–5 másodperc a heap dump elemzéséhez
Teljesítmény10–50 MB RAM-ot foglal elemzés közben2–10 MB RAM-ot foglal elemzés közben

A Shark fő előnye — nem tölti be a teljes heap dump-ot a memóriába, hanem minimális foglalásokkal járja be a referenciagráfját. Ez alkalmassá teszi a LeakCanary 2.x-et alacsony RAM-mal rendelkező eszközökön való használatra, az OutOfMemoryError kockázata nélkül az elemzés során.

A 2.x verzióban megjelent a heap dump fájlba exportálásának lehetősége is későbbi elemzéshez az Android Studio Memory Profiler-ben. Ehhez engedélyezni kell a dumpHeapWhenLeakFound beállítást az AppWatcher konfigurációjában.

Tipikus szivárgások, amelyeket a LeakCanary talál

A LeakCanary hatékonyan észleli az Androidra jellemző szivárgások több osztályát. A leggyakoribb az Activity-re mutató statikus referenciákon keresztüli szivárgás — a fejlesztők eltárolják az Activity kontextusára mutató referenciát egy singletonban, és az Activity-t nem tudja összegyűjteni a GC az életciklusának befejeződése után.

A második leggyakoribb kategória — nem regisztrált hallgatókon keresztüli szivárgások. Ha az onStart-ban meghívták a registerListener-t, de az onStop/onDestroy-ben nem hívták meg az unregisterListener-t — a hallgató objektumot a rendszer még az aktivitás megsemmisítése után is tartja. A LeakCanary egyértelműen mutatja, melyik hallgató és melyik rendszerszolgáltatásban maradt aktív.

kotlin
// Tipikus szivárgás: Activity elkapva egy singleton callback-jében
object AnalyticsManager {
    private var callback: ((String) -> Unit)? = null

    fun register(callback: (String) -> Unit) {
        this.callback = callback // erős referencia a callback-re
    }

    fun unregister() {
        callback = null // NE FELEJTSE EL meghívni onDestroy-ben!
    }
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        AnalyticsManager.register { event ->
            logEvent(event) // lambda elkapja a this-t
        }
        // ha nem hívja meg az unregister-t onDestroy-ben → Activity szivárgás
    }
}

A harmadik kategória — szivárgások Fragment-en keresztül a BackStack-ben. Ha a FragmentTransaction.addToBackStack() a Fragment eltávolítása nélkül kerül meghívásra visszatéréskor, a régi Fragment példányok a memóriában maradnak. A LeakCanary segít az ilyen rejtett szivárgások korai felderítésében a fejlesztés során.

Minden észlelt szivárgáshoz a LeakCanary leírást és javítási javaslatokat kínál. A 2.14-es verzióban integráció került hozzáadásra az Android Lint-tel — a könyvtár automatikusan feladatokat hozhat létre az issue tracker-ben, ha szivárgást észlel a CI-ben.

Gyakran ismételt kérdések

El kell távolítani a LeakCanary-t a release APK-ból?

Igen, feltétlenül. A LeakCanary a debugImplementation-en keresztül csatlakozik a build.gradle-ben, ami automatikusan kizárja a release buildből. Ha az implementation-en keresztül csatlakoztatja, a könyvtár bekerül a release APK-ba, és szivárgásokat fog mutatni a végfelhasználóknak — ez elfogadhatatlan.

Lassítja-e a LeakCanary az alkalmazás működését?

A teljesítményre gyakorolt hatás minimális. A LeakCanary csak a komponens onDestroy-je után aktiválódik, és nem avatkozik be a UI megjelenítésébe vagy az érintések feldolgozásába. Az egyetlen költség — a kényszerített GC rövid szünete (körülbelül 100 ms) és a heap dump írása szivárgáskor (másodperc századrészei).

Hogyan exportáljuk a LeakCanary jelentést?

A LeakCanary automatikusan elmenti a heap dump-ot HPROF formátumban az alkalmazás mappájába. A fájl exportálható az Android Studio-n keresztül: Device File Explorer → data/data/com.example/files/leakcanary/. Megtekintéshez nyissa meg a fájlt a Memory Profiler-ben a Capture → Open Heap Dump segítségével.

Működik a LeakCanary a Jetpack Compose-zal?

Igen, a 2.12-es verziótól kezdve a LeakCanary teljes mértékben támogatja a Jetpack Compose-t. A könyvtár követi a Composition kontextusokat és az State objektumokat, automatikusan észlelve a szivárgásokat a Composable függvényekben. Külön konfiguráció nem szükséges — a dobozból kivéve működik.

Tévedhet a LeakCanary (false positive)?

Téves riasztások lehetségesek, de ritkák. A LeakCanary háromszori GC-meghívást használ a szivárgás bejelentése előtt, ami kiküszöböli a legtöbb téves pozitív eredményt. Ha úgy gondolja, hogy a riasztás téves — hozzon létre egy IgnoredReference-t az adott osztályhoz a konfigurációban.

Összefoglalás

  • LeakCanary — szabványos könyvtár a memóriaszivárgások automatikus észlelésére Android-alkalmazásokban.
  • A könyvtár WeakReference-t és kényszerített GC-t használ az életciklusukat túlélő objektumok észlelésére.
  • Heap dump elemzése a beépített Shark motor által történik, amely referencialáncot épít a GC Root-tól a kiszivárgott objektumig.
  • Telepítés modern projektben — egy sor a build.gradle-ben: debugImplementation.
  • A LeakCanary 2.x teljesen újra lett írva Kotlinban, és 5–10-szer gyorsabb, mint az előző verzió.
  • Leggyakoribb szivárgások: statikus referenciák Activity-re, nem regisztrált hallgatók és Fragment a BackStack-ben.
  • Vezesse be a LeakCanary-t minden projekt debug-build-jébe — ez megelőzi a szivárgásokat éles környezetben.

Kulcsrakész mobilalkalmazást fejlesztünk

Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.

Projekt megbeszélése

Olvassa el is