Sobes.tech
Middle+

Πώς να εντοπίσετε την ύπαρξη διαρροής μνήμης κατά την ανάλυση ενός dump;

sobes.tech AI

Απάντηση από AI

Για την ανίχνευση διαρροών μνήμης σε ένα dump (αρχείο HPROF), χρησιμοποιούνται εργαλεία που αναλύουν το γράφημα αντικειμένων στη στοίβα. Βασικά βήματα:

  1. Λήψη dump μνήμης:

    • Μέσω του Memory Profiler του Android Studio.
    • Με την εντολή adb shell dumpheap <όνομα πακέτου> /data/local/tmp/dump.hprof.
    • Με την κλήση συστήματος Debug.dumpHprofData(filePath).
  2. Ανάλυση του dump:

    • Άνοιγμα του dump στο Android Studio: στον Memory Profiler ή μέσω του μενού "File" -> "Open".
    • Ανάλυση αντικειμένων: ταξινόμηση των αντικειμένων κατά μέγεθος (Shallow Size, Retained Size) και αριθμό αντιγράφων.
    • Αναζήτηση ύποπτων αντικειμένων: αναζητήστε κλάσεις που πρέπει να καταστραφούν (π.χ., Activity, Fragment, Contexts), αλλά έχουν πολλά αντίγραφα ή μεγάλο Retained Size.
    • Μελέτη της διαδρομής προς το αντικείμενο (Reference Chain): επιλέξτε ένα ύποπτο αντικείμενο και παρακολουθήστε το μονοπάτι του προς τα ριζικά αντικείμενα (GC roots). Αυτό θα δείξει ποιος διατηρεί την αναφορά, αποτρέποντας τη συλλογή απορριμμάτων.
    • Αναζήτηση στατικών αναφορών: τα στατικά πεδία συχνά αποτελούν πηγή διαρροών, αν αποθηκεύουν μακροχρόνιες αναφορές σε συμφραζόμενα ή προβολές.
    • Χρήση LeakCanary: η βιβλιοθήκη αυτοματοποιεί την ανίχνευση, το dump και την ανάλυση διαρροών σε πραγματικό χρόνο, παρέχοντας λεπτομερή περιγραφή της διαδρομής διαρροής.
  3. Ερμηνεία αποτελεσμάτων:

    • Μια μεγάλη διαδρομή προς το GC root που περιέχει αναφορές σε αντικείμενα που πρέπει να καταστραφούν υποδεικνύει πρόβλημα.
    • Αναφορές από στατικά πεδία, AsyncTask, χειριστές με καθυστερήσεις, listeners/callbacks που δεν έχουν αποεγγραφεί σωστά ή singleton σε δραστηριότητες ή προβολές συχνά αποτελούν αιτίες διαρροών.

Παράδειγμα ανάλυσης της διαδρομής προς το GC root στο Android Studio Memory Profiler:

// Παράδειγμα διαδρομής προς GC root που υποδεικνύει διαρροή
// android.app.Activity instance με mDestroyed=true
//   αναφορά σε android.widget.LinearLayout
//     αναφορά σε android.view.View $ListenerInfo
//       αναφορά σε com.example.MyActivity$1 (ανώνυμη κλάση που υλοποιεί View.OnClickListener)
//         αναφορά σε com.example.MyActivity (αναφορά που προκαλεί τη διαρροή)

Σε αυτό το παράδειγμα, μια ανώνυμη κλάση (ακούγοντας κλικ κουμπιού) διατηρεί μια έμμεση αναφορά στο MyActivity, παρόλο που η δραστηριότητα θα έπρεπε ήδη να έχει καταστραφεί (mDestroyed=true). Αυτός ο ακροατής φαίνεται να καταγράφεται ή να διατηρείται από ένα άλλο μακροχρόνιο αντικείμενο (π.χ., στατικό πεδίο ή singleton).