Heap Dump (dump σωρού) — ένα στιγμιότυπο της δυναμικής μνήμης της εφαρμογής που περιέχει πλήρεις πληροφορίες για όλα τα ζωντανά αντικείμενα: τις κλάσεις τους, μεγέθη, αμοιβαίες αναφορές και προσβασιμότητα από τους ριζικούς κόμβους (GC roots). Heap Dump είναι το βασικό εργαλείο ανάλυσης διαρροών μνήμης και βελτιστοποίησης κατανάλωσης πόρων. Σύμφωνα με το Android Developers, η ανάλυση heap dumps επιτρέπει τον εντοπισμό έως και 95% των διαρροών μνήμης, συμπεριλαμβανομένων κυκλικών αναφορών, ξεχασμένων listener και μη απελευθερωμένων στατικών αναφορών.
Κύρια σημεία
Heap dump είναι ένα πλήρες dump του σωρού (heap) της εικονικής μηχανής — της περιοχής μνήμης όπου τοποθετούνται όλα τα δυναμικά δημιουργούμενα αντικείμενα. Σε Java και Kotlin αυτό είναι Dalvik/ART στο Android, σε Swift και Objective-C — ο σωρός που διαχειρίζεται το ARC στο iOS. Το heap dump καταγράφει κάθε αντικείμενο, την κλάση του, μέγεθος, πεδία, αναφορές σε άλλα αντικείμενα και σημαίες προσβασιμότητας από GC roots (μεταβλητές στοίβας, στατικά πεδία, αναφορές JNI).
Ο κύριος σκοπός του heap dump είναι ο εντοπισμός διαρροών μνήμης. Μια διαρροή προκύπτει όταν η εφαρμογή συνεχίζει να διατηρεί αναφορές σε αντικείμενα που δεν χρειάζονται πλέον, εμποδίζοντας τη συλλογή τους από τον garbage collector (ή την απελευθέρωση μέσω ARC). Τυπικές αιτίες: listener συμβάντων που δεν καταργήθηκαν κατά την καταστροφή activity; singletons με αναφορές σε context; closures που συλλαμβάνουν self; στατικές συλλογές στις οποίες προστίθενται δεδομένα χωρίς διαγραφή. Το heap dump δίνει ακριβή εικόνα: ποια αντικείμενα είναι «ζωντανά», ποια είναι περιττά και ποιος ακριβώς αναφέρεται σε αυτά.
Σύμφωνα με δεδομένα του Google I/O, πάνω από 60% των αναφορών crash εφαρμογών Android σχετίζονται με OutOfMemoryError, και στο 80% των περιπτώσεων η βασική αιτία είναι μια διαρροή μνήμης που ανιχνεύεται μέσω heap dump. Για εφαρμογές iOS η κατάσταση είναι παρόμοια: οι διαρροές λόγω retain cycles είναι μια από τις συχνές αιτίες crashes που εντοπίζονται μέσω του εργαλείου Allocations στο Xcode.
Το heap dump πρέπει να εκτελείται στα ακόλουθα συμπτώματα: η εφαρμογή καταναλώνει μνήμη γραμμικά σε επαναλαμβανόμενες ενέργειες (πλοήγηση μπρος-πίσω μεταξύ οθονών); μετά την ολοκλήρωση μιας οθόνης, η μνήμη δεν επιστρέφει στο αρχικό επίπεδο; εμφανίζονται OutOfMemoryError ή προειδοποιήσεις memory warning στο iOS; η εφαρμογή τερματίζεται λόγω υπέρβασης ορίου μνήμης (EXC_RESOURCE_RESOURCE στο iOS). Η τακτική συλλογή heap dumps είναι μέρος του πρωτοκόλλου μηχανικής κουλτούρας σε μεγάλα κινητά έργα, όπως το Instagram και το Spotify.
Android Studio παρέχει το Memory Profiler — ένα ενσωματωμένο εργαλείο για λήψη heap dump σε πραγματικό χρόνο. Προσβάσιμο μέσω View → Tool Windows → Profiler. Μετά την εκκίνηση της εφαρμογής, επιλέξτε την περίοδο λειτουργίας, μεταβείτε στην καρτέλα Memory και κάντε κλικ στο Dump Java Heap. Το Android Studio διακόπτει την εφαρμογή, εκτελεί dump του ART σωρού και φορτώνει το αποτέλεσμα για ανάλυση. Το αρχείο dump έχει μορφή .hprof — πρότυπο HPROF συμβατό με τους περισσότερους αναλυτές μνήμης.
Μετά τη φόρτωση του dump, το Android Studio εμφανίζει έναν πίνακα αντικειμένων με στήλες: Allocations (αριθμός στιγμιοτύπων), Native Size (μνήμη εκτός ART σωρού), Shallow Size (μνήμη του ίδιου του αντικειμένου), Retained Size (μνήμη αντικειμένου με ολόκληρο το υπογράφημα). Φιλτράρισμα κατά όνομα κλάσης, ταξινόμηση κατά retained size και αναζήτηση κατά πακέτα επιτρέπουν γρήγορη εύρεση προβληματικών περιοχών.
// Τυπική διαρροή — listener δεν καταργήθηκε στο onDestroy
class MainActivity : AppCompatActivity() {
private val sensorManager by lazy {
getSystemService(SENSOR_SERVICE) as SensorManager
}
private val listener = MySensorListener()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sensorManager.registerListener(listener,
sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_NORMAL)
}
override fun onDestroy() {
super.onDestroy()
// ❌ Παραλείφθηκε το sensorManager.unregisterListener(listener)
// → Το Activity δεν θα συλλεχθεί από GC, το heap dump θα δείξει διαρροή
}
}
Η καρτέλα Dominator Tree δείχνει αντικείμενα που διατηρούν τη μεγαλύτερη ποσότητα μνήμης. Εάν ένα αντικείμενο διαγραφεί από το dominator tree, όλη η μνήμη που διατηρεί γίνεται διαθέσιμη για συλλογή. Αυτό είναι το βασικό εργαλείο: αντί να εξετάζετε χιλιάδες αντικείμενα, εστιάζετε σε 10-20 που ελέγχουν το 80-90% της μνήμης. Σύμφωνα με την Google, η ανάλυση dominator tree είναι ο πιο αποτελεσματικός τρόπος εύρεσης σημείου διαρροής, μειώνοντας τον χρόνο ανάλυσης από ώρες σε λεπτά.
Xcode Instruments παρέχει δύο εργαλεία για εργασία με heap dump: Allocations — λήψη dump σωρού με γράφημα κατανάλωσης σε πραγματικό χρόνο; Leaks — αυτόματη αναζήτηση διαρροών μέσω ανάλυσης retain cycles. Το Allocations εμφανίζει όλα τα αντικείμενα στο σωρό, το μέγεθός τους, αριθμό δημιουργιών (allocations) και απελευθερώσεων (deallocations). Η διαφορά μεταξύ αριθμού δημιουργιών και απελευθερώσεων για μια συγκεκριμένη κλάση υποδεικνύει πιθανή διαρροή.
Η λήψη heap dump στο Allocations γίνεται με το κουμπί Snapshot Memory — το εργαλείο διακόπτει την εφαρμογή και λαμβάνει πλήρες dump. Στη συνέχεια, είναι διαθέσιμες οι τυπικές προβολές: λίστα αντικειμένων ανά κλάση, δέντρο κλήσεων (call tree) για κάθε αντικείμενο και γεννήτρια αναφορών. Σε αντίθεση με το Android Studio, το Xcode δεν χρησιμοποιεί .hprof, αλλά αποθηκεύει δεδομένα στη δική του μορφή .trace, συμβατή με το Instruments.
// Τυπική διαρροή iOS — retain cycle μέσω closure
class NetworkManager {
var onComplete: ((Data) -> Void)?
func startRequest() {
// ❌ Το closure συλλαμβάνει self — retain cycle
onComplete = { data in
self.process(data)
}
}
func process(_ data: Data) {}
}
Το εργαλείο Leaks ανιχνεύει αυτόματα retain cycles και διαρροές μέσω ανάλυσης γράφου αναφορών. Σημειώνει τα αντικείμενα που παρουσιάζουν διαρροή με μωβ εικονίδιο και δείχνει τη διαδρομή προς τη ρίζα (GC root). Για την εξάλειψη ενός retain cycle, αρκεί να προστεθεί [weak self] ή [unowned self] στο closure. Η τακτική εκτέλεση του εργαλείου Leaks είναι υποχρεωτικό στάδιο CI σε ομάδες που χρησιμοποιούν Swift για ανάπτυξη iOS.
// Διόρθωση — αδύναμη αναφορά σε self
onComplete = { [weak self] data in
guard let self else { return }
self.process(data)
}
Για σωστή ανάλυση heap dump είναι απαραίτητο να κατανοήσετε τρεις βασικές μετρικές. Shallow size — ο όγκος μνήμης που καταλαμβάνεται άμεσα από το αντικείμενο: τα πεδία του, η κεφαλίδα (header) και η στοίχιση. Για ένα τυπικό αντικείμενο Java/Kotlin, το shallow size είναι 16-40 byte. Retained size — το shallow size του αντικειμένου συν το συνολικό shallow size όλων των αντικειμένων που είναι προσβάσιμα μόνο μέσω αυτού του αντικειμένου (δηλαδή θα γίνουν σκουπίδι κατά τη διαγραφή του). Ακριβώς το retained size δείχνει την πραγματική επίδραση του αντικειμένου στην κατανάλωση μνήμης.
| Μετρική | Περιγραφή | Παράδειγμα |
|---|---|---|
| Shallow size | Μέγεθος του ίδιου του αντικειμένου σε byte | Bitmap (100×100) = 40 016 B |
| Retained size | Shallow size + ό,τι διατηρεί | Activity με View Tree = 2-5 MB |
| Deep size | Retained size + ένθετα αντικείμενα από άλλα γραφήματα | ScrollView με προσαρμογέα = 10-50 MB |
Dominator tree — μια δομή όπου κάθε αντικείμενο αναφέρεται στον «κυρίαρχό» του — το αντικείμενο που ελέγχει την προσβασιμότητά του. Εάν ο κυρίαρχος διαγραφεί, όλα τα αντικείμενα του υποδέντρου του γίνονται σκουπίδι. Η ανάλυση dominator tree είναι ο ταχύτερος τρόπος για να βρεθεί το αντικείμενο που διατηρεί την περισσότερη μνήμη. Σύμφωνα με το Eclipse MAT (Memory Analyzer Tool), το 90% των διαρροών ανιχνεύονται μέσω προβολής των top-20 dominator tree μέσα σε 5 λεπτά.
Η διαδικασία ανάλυσης διαρροής μέσω heap dump αποτελείται από πολλά βήματα. Βήμα 1: εκτελέστε την ενέργεια που θα πρέπει να απελευθερώσει μνήμη (κλείστε την οθόνη, ολοκληρώστε τη λειτουργία). Βήμα 2: καλέστε το GC (System.gc() στο Android, υποχρεωτικό snapshot στο Xcode) και κάντε heap dump. Βήμα 3: βρείτε αντικείμενα που θα έπρεπε να έχουν καταστραφεί (π.χ. ένα στιγμιότυπο Activity μετά το finish). Βήμα 4: για το ύποπτο αντικείμενο, εκτελέστε Path to GC Roots — την αλυσίδα αναφορών που κρατά το αντικείμενο ζωντανό. Η τελευταία αναφορά στην αλυσίδα είναι η αιτία της διαρροής.
Η λειτουργία Path to GC Roots είναι διαθέσιμη στο Android Studio Profiler, το Eclipse MAT και το Xcode Instruments. Δείχνει τη συντομότερη αλυσίδα αναφορών από GC root προς το προβληματικό αντικείμενο. Εξαιρώντας τις αδύναμες (weak) και μαλακές (soft) αναφορές, λαμβάνετε μόνο ισχυρές (strong) αναφορές — αυτές που πραγματικά εμποδίζουν τη συλλογή. Σύμφωνα με στατιστικά της Square Engineering, το 70% των διαρροών σε εφαρμογές Android προκαλούνται από μόνο δύο μοτίβα: στατικές αναφορές σε Activity ή Context και εγγεγραμμένοι αλλά μη καταργημένοι listener.
// Παράδειγμα διαρροής μέσω στατικής αναφοράς
object AppCache {
private val cache = mutableMapOf<String, Any>()
fun storeActivityReference(activity: Activity) {
cache["current_activity"] = activity // ❌ Διαρροή!
}
}
// Διόρθωση: αδύναμη αναφορά
object AppCacheFixed {
private val cache = mutableMapOf<String, WeakReference<Any>>()
}
Η τεχνική comparison mode — μια από τις πιο αποτελεσματικές μεθόδους εύρεσης διαρροών. Κάντε heap dump πριν και μετά από μια επαναλαμβανόμενη ενέργεια (π.χ. πέντε πλοηγήσεις σε οθόνη και επιστροφή). Συγκρίνετε τον αριθμό στιγμιοτύπων βασικών κλάσεων: εάν ο αριθμός Activity αυξήθηκε, ενώ όλες οι δραστηριότητες έκλεισαν — αυτό είναι διαρροή. Το Android Studio και το Eclipse MAT υποστηρίζουν αυτόματη σύγκριση dumps με επισήμανση διαφορών. Σύμφωνα με την Google, η σύγκριση dumps επιτρέπει την εύρεση διαρροών που είναι αόρατες σε μία εφάπαξ ανάλυση λόγω συσσώρευσης αποτελέσματος.
Με βάση την ανάλυση heap dumps σε πραγματικά έργα, έχουν αναπτυχθεί αποδεδειγμένες πρακτικές βελτιστοποίησης μνήμης. Χρησιμοποιήστε WeakReference για προσωρινές μνήμες, callback και αναφορές σε context σε μακρόβια αντικείμενα. Καταργήστε τους listener στο onPause/onDestroy για Android και deinit για iOS. Αποφύγετε μεγάλες στατικές συλλογές — εάν είναι απαραίτητες, χρησιμοποιήστε LruCache με περιορισμό μεγέθους. Βελτιστοποιήστε Bitmap: φορτώστε εικόνες με σωστό inSampleSize, χρησιμοποιήστε Glide ή Picasso με προσωρινή μνήμη δίσκου.
Συμπεριλάβετε τακτική λήψη heap dump στο CI. Διαμορφώστε μια εργασία που εκτελεί instrumented UI tests, εκτελεί βασικά σενάρια χρήστη και συγκρίνει το heap dump με baseline. Εάν το retained size αυξηθεί περισσότερο από 5% σε σχέση με το baseline, η build επισημαίνεται ως παλινδρόμηση. Αυτή η προσέγγιση εφαρμόζεται στην Airbnb, την Uber και άλλες εταιρείες με υψηλές απαιτήσεις ποιότητας. Σύμφωνα με την Uber Engineering, η εισαγωγή αυτόματης ανάλυσης heap dump στο CI μείωσε τον αριθμό σφαλμάτων που σχετίζονται με μνήμη κατά 70% σε ένα τρίμηνο.
// Παράδειγμα Gradle εργασίας για αυτόματο heap dump σε CI
task profileMemory(type: Exec) {
commandLine 'adb', 'shell',
'am start -n com.example/.MainActivity'
// Αναμονή φόρτωσης
doLast {
exec { commandLine 'adb', 'shell',
'am broadcast -a com.example.DUMP_HEAP' }
}
}
Συχνές Ερωτήσεις
Shallow size — το μέγεθος του ίδιου του αντικειμένου (πεδία + κεφαλίδα). Retained size — το μέγεθος του αντικειμένου συν όλα τα αντικείμενα που θα γίνουν σκουπίδι κατά τη διαγραφή του. Το retained size είναι ο κύριος δείκτης της επίδρασης του αντικειμένου στην κατανάλωση μνήμης.
Μέσω του Android Studio Profiler επιλέξτε συσκευή και διεργασία, κάντε κλικ στο Dump Java Heap. Εναλλακτικά — μέσω γραμμής εντολών: adb shell am dumpheap PID /sdcard/dump.hprof, στη συνέχεια adb pull.
Το heap dump περιλαμβάνει όλα τα ζωντανά αντικείμενα. Εάν η εφαρμογή χρησιμοποιεί προσωρινές μνήμες, Bitmap ή επεξεργάζεται μεγάλα δεδομένα, το dump μπορεί να φτάσει εκατοντάδες megabyte. Φιλτράρετε κατά κλάση ή χρησιμοποιήστε το Eclipse MAT για φόρτωση μόνο του ευρετηρίου.
Ναι, χρησιμοποιήστε το Eclipse MAT (Memory Analyzer Tool) — ένα δωρεάν εργαλείο για ανάλυση .hprof. Υποστηρίζει dominator tree, path to GC roots, σύγκριση dumps και αυτόματη αναζήτηση διαρροών μέσω Leak Suspects Report.
Το ίδιο το dump — ναι, επειδή η λήψη dump διακόπτει όλα τα νήματα (stop-the-world). Χωρίς dump — όχι. Κάντε dump υπό ελεγχόμενες συνθήκες (περιβάλλον δοκιμών, CI), όχι σε παραγωγή.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης