LeakCanary — τι είναι, βιβλιοθήκη για αναζήτηση διαρροών στο Android

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-03-30 Χρόνος ανάγνωσης: 9 λεπ

LeakCanary — είναι μια βιβλιοθήκη ανοιχτού κώδικα από την Square για αυτόματη ανίχνευση διαρροών μνήμης σε εφαρμογές Android. Ενσωματώνεται στη διαδικασία ανάπτυξης και σε πραγματικό χρόνο παρακολουθεί τον κύκλο ζωής των Activity, Fragment, ViewModel και άλλων συστατικών, σηματοδοτώντας διαρροές αμέσως μετά την εμφάνισή τους. Σύμφωνα με δεδομένα του Square Open Source, η βιβλιοθήκη χρησιμοποιείται σε χιλιάδες έργα και θεωρείται το de facto πρότυπο για τη διάγνωση μνήμης στο 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 είναι η ανίχνευση της κατάστασης όταν ένα αντικείμενο συνεχίζει να υπάρχει στη μνήμη αφού ο κύκλος ζωής του έχει ολοκληρωθεί. Αυτό είναι τυπικό για διαρροές μέσω στατικών πεδίων, singletons, μη καταγεγραμμένων callbacks, ανώνυμων κλάσεων και κλεισιμάτων που συλλαμβάνουν εξωτερικά αντικείμενα.

Γιατί το LeakCanary είναι σημαντικό για την ανάπτυξη Android

Οι διαρροές μνήμης στο Android είναι πιο κρίσιμες από ό,τι στην επιφάνεια εργασίας λόγω της περιορισμένης ποσότητας RAM στις κινητές συσκευές. Ακόμη και μια διαρροή 5–10 MB σε κάθε εναλλαγή οθόνης μπορεί να οδηγήσει σε OutOfMemoryError μετά από 30–40 λεπτά χρήσης της εφαρμογής. Το LeakCanary ανιχνεύει τέτοια προβλήματα στο στάδιο ανάπτυξης, χωρίς να περιμένει κατάρρευση στην παραγωγή.

Πώς λειτουργεί το LeakCanary;

LeakCanary χρησιμοποιεί αδύναμες αναφορές (WeakReference) σε συνδυασμό με αναγκαστική κλήση του garbage collector. Όταν το 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 — είναι ο ενσωματωμένος αναλυτής heap dump στο LeakCanary 2.x, γραμμένος σε Kotlin. Σε αντίθεση με τον προηγούμενο αναλυτή HAHA, το Shark δεν φορτώνει ολόκληρο το αρχείο HPROF στη μνήμη, αλλά περιηγείται στο γράφημα αντικειμένων του με ελάχιστες εκχωρήσεις. Αυτό μειώνει την κατανάλωση RAM κατά την ανάλυση από 50 MB σε 2–5 MB και συντομεύει τον χρόνο ανάλυσης από 30 δευτερόλεπτα σε 1–3 δευτερόλεπτα.

Πώς να εγκαταστήσετε και να ρυθμίσετε το LeakCanary;

Η εγκατάσταση του LeakCanary 2.x σε ένα σύγχρονο έργο Android διαρκεί μία γραμμή στο build.gradle. Η βιβλιοθήκη χρησιμοποιεί ContentProvider για αυτόματη αρχικοποίηση — δεν χρειάζεται να τροποποιήσετε την κλάση Application ή να προσθέσετε κώδικα στο MainActivity. Η σύνδεση γίνεται μόνο για debug-build, ώστε να μην υπάρχει περιττός κώδικας στο release APK.

groovy
// build.gradle (app/module)
dependencies {
    // debugImplementation — βιβλιοθήκη μόνο για debug-build
    debugImplementation "com.squareup.leakcanary:leakcanary-android:2.14"
}

Μετά την προσθήκη της εξάρτησης και την εκ νέου δημιουργία του έργου, το LeakCanary εμφανίζεται αυτόματα στην εφαρμογή. Κατά την πρώτη εκτέλεση, η βιβλιοθήκη εμφανίζει μια ειδοποίηση συστήματος σχετικά με την ενεργοποίηση. Όλες οι ανιχνευμένες διαρροές εμφανίζονται ως ειδοποιήσεις — κλικ στην ειδοποίηση ανοίγει την οθόνη με τη λεπτομερή αναφορά (LeakTrace).

Για προσαρμογή, μπορείτε να δημιουργήσετε το δικό σας AppWatcherInstaller και να παρακάμψετε παραμέτρους: χρονικό όριο αναμονής GC, λίστα τύπων αντικειμένων προς παρακολούθηση, ενεργοποίηση αποθήκευσης heap dump στον δίσκο. Ωστόσο, για το 90% των έργων, η προεπιλεγμένη διαμόρφωση είναι βέλτιστη.

Ρύθμιση για coroutine και Jetpack Compose

Από την έκδοση 2.12, το LeakCanary υποστηρίζει αυτόματη παρακολούθηση ViewModel, πεδίων coroutine και αντικειμένων State Compose. Δεν απαιτούνται πρόσθετες εξαρτήσεις — η βιβλιοθήκη εντοπίζει μόνη της ποια συστατικά Jetpack χρησιμοποιούνται στο έργο και ενεργοποιεί τους αντίστοιχους ανιχνευτές.

Πώς να διαβάσετε την αναφορά LeakCanary

Η αναφορά LeakCanary (LeakTrace) — είναι μια πολυγραμμική αλυσίδα αναφορών από GC Root έως το αντικείμενο που διέρρευσε. Κάθε γραμμή δείχνει την κλάση και το πεδίο μέσω των οποίων περνά η ισχυρή αναφορά. Ο προγραμματιστής πρέπει να διαβάζει την αλυσίδα από κάτω προς τα πάνω: κάτω γραμμή — αντικείμενο που διέρρευσε, πάνω γραμμή — σημείο εισόδου (GC Root).

Ένα τυπικό LeakTrace μοιάζει με αυτό: GC Root → στατικό πεδίο Application → singleton → callback → Activity. Εάν ο προγραμματιστής βλέπει μια τέτοια αλυσίδα, το πρόβλημα είναι σαφές: το singleton κρατά ένα callback που συνέλαβε μια αναφορά στο Activity. Λύση — αντικαταστήστε την ισχυρή αναφορά με αδύναμη στο singleton.

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. Λύση — κάντε το callback αδύναμη αναφορά ή ακυρώστε το στο 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 του 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 σε ένα singleton, και το Activity δεν μπορεί να συλλεχθεί από τον GC μετά την ολοκλήρωση του κύκλου ζωής του.

Η δεύτερη πιο συχνή κατηγορία — διαρροές μέσω μη καταγεγραμμένων ακροατών. Εάν στο onStart κλήθηκε registerListener, αλλά στο onStop/onDestroy δεν κλήθηκε unregisterListener — το αντικείμενο-ακροατής συγκρατείται από το σύστημα ακόμη και μετά την καταστροφή της δραστηριότητας. Το LeakCanary δείχνει με σαφήνεια ποιος ακροατής και σε ποια υπηρεσία συστήματος παρέμεινε ενεργός.

kotlin
// Τυπική διαρροή: Activity συλληφθείσα σε callback singleton
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) // η lambda συλλαμβάνει το this
        }
        // εάν δεν καλέσετε unregister στο onDestroy → διαρροή Activity
    }
}

Η τρίτη κατηγορία — διαρροές μέσω Fragment στο BackStack. Εάν το FragmentTransaction.addToBackStack() καλείται χωρίς αφαίρεση του Fragment κατά την επιστροφή, τα παλιά στιγμιότυπα Fragment παραμένουν στη μνήμη. Το LeakCanary βοηθά στην ανίχνευση τέτοιων κρυφών διαρροών στα πρώτα στάδια ανάπτυξης.

Για κάθε ανιχνευμένη διαρροή, το LeakCanary προσφέρει περιγραφή και συστάσεις για διόρθωση. Στην έκδοση 2.14 προστέθηκε ενσωμάτωση με το Android Lint — η βιβλιοθήκη μπορεί να δημιουργεί αυτόματα εργασίες στο issue tracker κατά την ανίχνευση διαρροής στο CI.

Συχνές ερωτήσεις

Πρέπει να αφαιρεθεί το LeakCanary από το release APK;

Ναι, υποχρεωτικά. Το LeakCanary συνδέεται μέσω debugImplementation στο build.gradle, το οποίο το αποκλείει αυτόματα από την έκδοση release. Εάν το συνδέσετε μέσω implementation, η βιβλιοθήκη θα μπει στο release APK και θα εμφανίζει διαρροές στους τελικούς χρήστες — αυτό είναι απαράδεκτο.

Επιβραδύνει το LeakCanary τη λειτουργία της εφαρμογής;

Η επίδραση στην απόδοση είναι ελάχιστη. Το LeakCanary ενεργοποιείται μόνο μετά το onDestroy του συστατικού και δεν παρεμβαίνει στην απόδοση UI ή στην επεξεργασία αφής. Το μόνο κόστος — μια σύντομη παύση του εξαναγκασμένου GC (περίπου 100 ms) και η εγγραφή 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 πριν από τη δήλωση διαρροής, η οποία εξαλείφει τα περισσότερα ψευδώς θετικά. Εάν πιστεύετε ότι η ενεργοποίηση είναι ψευδής — δημιουργήστε ένα IgnoredReference για τη συγκεκριμένη κλάση στη διαμόρφωση.

Σύνοψη

  • LeakCanary — πρότυπη βιβλιοθήκη για αυτόματη ανίχνευση διαρροών μνήμης σε εφαρμογές Android.
  • Η βιβλιοθήκη χρησιμοποιεί WeakReference και εξαναγκασμένο GC για την ανίχνευση αντικειμένων που επέζησαν του κύκλου ζωής τους.
  • Το Heap dump αναλύεται από την ενσωματωμένη μηχανή Shark, η οποία χτίζει μια αλυσίδα αναφορών από GC Root έως το αντικείμενο που διέρρευσε.
  • Εγκατάσταση σε σύγχρονο έργο — μία γραμμή στο build.gradle: debugImplementation.
  • Το LeakCanary 2.x ξαναγράφτηκε πλήρως σε Kotlin και λειτουργεί 5–10 φορές γρηγορότερα από την προηγούμενη έκδοση.
  • Οι πιο συχνές διαρροές: στατικές αναφορές σε Activity, μη καταγεγραμμένοι ακροατές και Fragment στο BackStack.
  • Εφαρμόστε το LeakCanary στο debug-build κάθε έργου — αυτό θα αποτρέψει διαρροές στην παραγωγή.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης