Heap Dump (kupacdump) — az alkalmazás dinamikus memóriájának pillanatképe, amely teljes információt tartalmaz az összes élő objektumról: osztályaikról, méreteikről, kölcsönös hivatkozásaikról és a gyökércsomópontoktól (GC roots) való elérhetőségükről. Heap Dump a memóriaszivárgások elemzésének és az erőforrás-felhasználás optimalizálásának alapvető eszköze. A Android Developers adatai szerint a heap dumpok elemzése lehetővé teszi a memóriaszivárgások akár 95%-ának felderítését, beleértve a ciklikus hivatkozásokat, elfelejtett listenereket és fel nem szabadított statikus hivatkozásokat.
Főbb pontok
Heap dump a virtuális gép kupacának (heap) teljes dumpja — az a memóriaterület, ahol az összes dinamikusan létrehozott objektum elhelyezkedik. Java és Kotlin esetén ez a Dalvik/ART Androidon, Swift és Objective-C esetén az ARC által kezelt kupac iOS-en. A heap dump rögzíti az egyes objektumokat, azok osztályát, méretét, mezőit, más objektumokra mutató hivatkozásait és a GC roots-októl (veremváltozók, statikus mezők, JNI-hivatkozások) való elérhetőség jelzőit.
A heap dump fő célja a memóriaszivárgások felderítése. Szivárgás akkor keletkezik, amikor az alkalmazás továbbra is hivatkozásokat tart fenn olyan objektumokra, amelyekre már nincs szükség, megakadályozva azok összegyűjtését a garbage collector (vagy az ARC általi felszabadítását) által. Tipikus okok: eseményfigyelők, amelyek nem lettek törölve az activity megsemmisülésekor; szingletonok kontextusra mutató hivatkozásokkal; closure-ök, amelyek megfogják a self-et; statikus gyűjtemények, amelyekhez adatokat adnak hozzá törlés nélkül. A heap dump pontos képet ad: mely objektumok „élnek", melyek feleslegesek, és ki pontosan hivatkozik rájuk.
A Google I/O adatai szerint az Android-alkalmazások crash-jelentéseinek több mint 60%-a kapcsolódik az OutOfMemoryError-hoz, és az esetek 80%-ában a fő ok egy heap dump segítségével felderíthető memóriaszivárgás. Az iOS-alkalmazások esetében a helyzet hasonló: a retain cycles okozta szivárgások a gyakori összeomlások egyik oka, amelyeket az Xcode Allocations instrumentuma segítségével lehet azonosítani.
Heap dumprot a következő tünetek esetén kell végezni: az alkalmazás lineárisan fogyaszt memóriát ismétlődő műveletek során (oda-vissza navigálás a képernyők között); a képernyő befejezése után a memória nem tér vissza az eredeti szintre; OutOfMemoryError vagy memory warning figyelmeztetések jelennek meg iOS-en; az alkalmazás a memóriakorlát túllépése miatt megszakad (EXC_RESOURCE_RESOURCE iOS-en). A heap dumpok rendszeres gyűjtése a mérnöki kultúra protokolljának része a nagy mobilprojektekben, mint az Instagram és a Spotify.
Android Studio Memory Profilert biztosít — egy beépített eszközt a heap dump valós idejű rögzítéséhez. Elérhető a View → Tool Windows → Profiler menüponton keresztül. Az alkalmazás elindítása után válassza ki a munkamenetet, lépjen a Memory fülre, és kattintson a Dump Java Heap gombra. Az Android Studio felfüggeszti az alkalmazást, végrehajtja az ART kupac dumpját, és betölti az eredményt elemzésre. A dump fájl formátuma .hprof — a HPROF szabvány, amely kompatibilis a legtöbb memóriaelemzővel.
A dump betöltése után az Android Studio egy objektumtáblázatot jelenít meg oszlopokkal: Allocations (példányok száma), Native Size (memória az ART kupacon kívül), Shallow Size (magának az objektumnak a memóriája), Retained Size (az objektum memóriája a teljes algráffal). Osztálynév szerinti szűrés, retained size szerinti rendezés és csomagok szerinti keresés lehetővé teszi a problémás területek gyors megtalálását.
// Tipikus szivárgás — listener nem lett leiratkozva onDestroy-ban
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) kimaradt
// → Az Activity-t nem gyűjti be a GC, a heap dump mutatja a szivárgást
}
}
A Dominator Tree fül azokat az objektumokat mutatja, amelyek a legtöbb memóriát tartják. Ha egy objektumot törölnek a dominator tree-ből, az általa tartott összes memória elérhetővé válik a gyűjtés számára. Ez a kulcsfontosságú eszköz: ahelyett, hogy több ezer objektumot vizsgálna meg, 10–20 objektumra összpontosít, amelyek a memória 80–90%-át irányítják. A Google szerint a dominator tree elemzés a leghatékonyabb módja a szivárgási pont megtalálásának, ami az elemzési időt órákról percekre csökkenti.
Xcode Instruments két eszközt kínál a heap dump-pal való munkához: Allocations — a kupacdump rögzítése valós idejű fogyasztási grafikonnal; Leaks — a szivárgások automatikus keresése retain cycles elemzésével. Az Allocations megjeleníti az összes objektumot a kupacban, azok méretét, a létrehozások (allocations) és felszabadítások (deallocations) számát. Egy adott osztály létrehozásainak és felszabadításainak száma közötti különbség potenciális szivárgást jelez.
A heap dump rögzítése az Allocations-ben a Snapshot Memory gombbal történik — az eszköz felfüggeszti az alkalmazást, és teljes dumprot készít. Ezt követően elérhetők a szabványos nézetek: objektumok listája osztályok szerint, hívási fa (call tree) minden objektumhoz és jelentésgenerátor. Az Android Studio-tól eltérően az Xcode nem használ .hprof-ot, hanem saját .trace formátumban tárolja az adatokat, amely kompatibilis az Instruments-szel.
// Tipikus iOS-szivárgás — retain cycle closure-en keresztül
class NetworkManager {
var onComplete: ((Data) -> Void)?
func startRequest() {
// ❌ A closure megfogja a self-et — retain cycle
onComplete = { data in
self.process(data)
}
}
func process(_ data: Data) {}
}
A Leaks instrumentum automatikusan észleli a retain cycle-öket és szivárgásokat a hivatkozási gráf elemzésével. A szivárgó objektumokat lila ikonnal jelöli, és megmutatja a gyökérhez (GC root) vezető utat. A retain cycle megszüntetéséhez elegendő a [weak self] vagy [unowned self] hozzáadása a closure-höz. A Leaks instrumentum rendszeres futtatása kötelező CI-lépés azokban a csapatokban, amelyek Swiftet használnak iOS-fejlesztéshez.
// Javítás — gyenge hivatkozás self-re
onComplete = { [weak self] data in
guard let self else { return }
self.process(data)
}
A heap dump helyes elemzéséhez három kulcsfontosságú mutatót kell megérteni. Shallow size — az objektum által közvetlenül elfoglalt memória mennyisége: mezői, fejléce (header) és igazítása. Egy tipikus Java/Kotlin objektum esetében a shallow size 16–40 bájt. Retained size — az objektum shallow size-ja plusz az összes olyan objektum teljes shallow size-ja, amelyek csak ezen az objektumon keresztül érhetők el (azaz törlésekor szemétté válnak). Pontosan a retained size mutatja az objektum valós hatását a memóriafogyasztásra.
| Mutató | Leírás | Példa |
|---|---|---|
| Shallow size | Az objektum saját mérete bájtokban | Bitmap (100×100) = 40 016 B |
| Retained size | Shallow size + minden, amit tart | Activity View Tree-vel = 2–5 MB |
| Deep size | Retained size + beágyazott objektumok más gráfokból | ScrollView adapterrel = 10–50 MB |
Dominator tree — egy struktúra, ahol minden objektum a „dominatorára" mutat — arra az objektumra, amely az elérhetőségét ellenőrzi. Ha a dominator törlésre kerül, a részfájának összes objektuma szemétté válik. A dominator tree elemzés a leggyorsabb módja annak, hogy megtaláljuk a legtöbb memóriát tartó objektumot. Az Eclipse MAT (Memory Analyzer Tool) szerint a szivárgások 90%-a a top-20 dominator tree 5 perces áttekintésével észlelhető.
A szivárgás elemzésének folyamata heap dump segítségével több lépésből áll. 1. lépés: hajtsa végre a műveletet, amelynek fel kellene szabadítania a memóriát (zárja be a képernyőt, fejezze be a műveletet). 2. lépés: hívja meg a GC-t (System.gc() Androidon, kényszerített snapshot Xcode-ban), és készítsen heap dumprot. 3. lépés: keresse meg azokat az objektumokat, amelyeknek meg kellett volna semmisülniük (pl. egy Activity példány a finish után). 4. lépés: a gyanús objektumhoz futtassa a Path to GC Roots-ot — a hivatkozások láncát, amely életben tartja az objektumot. A lánc utolsó hivatkozása a szivárgás oka.
A Path to GC Roots funkció elérhető az Android Studio Profiler-ben, az Eclipse MAT-ban és a Xcode Instruments-ben. Megmutatja a legrövidebb hivatkozási láncot a GC gyökértől a problémás objektumig. A gyenge (weak) és lágy (soft) hivatkozások kizárásával csak az erős (strong) hivatkozásokat kapja meg — azokat, amelyek valóban akadályozzák a gyűjtést. A Square Engineering statisztikái szerint az Android-alkalmazásokban a szivárgások 70%-át mindössze két minta okozza: statikus hivatkozások Activity-re vagy Context-re, valamint regisztrált, de le nem iratkozott listenerek.
// Példa szivárgásra statikus hivatkozáson keresztül
object AppCache {
private val cache = mutableMapOf<String, Any>()
fun storeActivityReference(activity: Activity) {
cache["current_activity"] = activity // ❌ Szivárgás!
}
}
// Javítás: gyenge hivatkozás
object AppCacheFixed {
private val cache = mutableMapOf<String, WeakReference<Any>>()
}
A comparison mode technika — az egyik leghatékonyabb módszer a szivárgások megtalálására. Készítsen heap dumprot egy ismétlődő művelet előtt és után (pl. öt navigáció egy képernyőre és vissza). Hasonlítsa össze a kulcsfontosságú osztályok példányainak számát: ha az Activity-k száma nőtt, miközben az összes aktivitás be volt zárva — ez szivárgás. Az Android Studio és az Eclipse MAT támogatja a dumpok automatikus összehasonlítását a különbségek kiemelésével. A Google szerint a dumpok összehasonlítása lehetővé teszi az egyszeri elemzés során láthatatlan szivárgások megtalálását a hatás felhalmozódása révén.
A valós projektekben végzett heap dump elemzések alapján bevált memóriaoptimalizálási gyakorlatokat dolgoztak ki. Használjon WeakReference-t gyorsítótárakhoz, visszahívásokhoz és kontextusra mutató hivatkozásokhoz hosszú életű objektumokban. Iratkozza le a listenereket az onPause/onDestroy-ban Android esetén és a deinit-ben iOS esetén. Kerülje a nagy statikus gyűjteményeket — ha szükségesek, használjon LruCache-t méretkorlátozással. Optimalizálja a Bitmap-eket: töltse be a képeket megfelelő inSampleSize-szal, használjon Glide-ot vagy Picassót lemezgyorsítótárral.
Foglalja bele a rendszeres heap dump rögzítést a CI-ba. Konfiguráljon egy feladatot, amely instrumentált UI-teszteket futtat, végrehajtja a kulcsfontosságú felhasználói forgatókönyveket, és összehasonlítja a heap dumprot a baseline-nel. Ha a retained size több mint 5%-kal nőtt a baseline-hez képest, a build regresszióként lesz megjelölve. Ezt a megközelítést alkalmazza az Airbnb, az Uber és más magas minőségi követelményekkel rendelkező vállalatok. Az Uber Engineering szerint a heap dump automatikus elemzésének CI-ba történő bevezetése 70%-kal csökkentette a memóriával kapcsolatos hibák számát egy negyedév alatt.
// Példa Gradle-feladatra automatikus heap dumphoz CI-ban
task profileMemory(type: Exec) {
commandLine 'adb', 'shell',
'am start -n com.example/.MainActivity'
// Betöltés várakozás
doLast {
exec { commandLine 'adb', 'shell',
'am broadcast -a com.example.DUMP_HEAP' }
}
}
Gyakran Ismételt Kérdések
Shallow size — az objektum saját mérete (mezők + fejléc). Retained size — az objektum mérete plusz az összes objektumé, amelyek törlésekor szemétté válnak. A retained size a fő mutatója az objektum memóriafogyasztásra gyakorolt hatásának.
Az Android Studio Profiler-ben válassza ki az eszközt és a folyamatot, kattintson a Dump Java Heap gombra. Alternatív megoldás — parancssoron keresztül: adb shell am dumpheap PID /sdcard/dump.hprof, majd adb pull.
A heap dump az összes élő objektumot tartalmazza. Ha az alkalmazás gyorsítótárakat, Bitmap-eket használ vagy nagy adatokat dolgoz fel, a dump elérheti a több száz megabájtot. Szűrjön osztályok szerint, vagy használja az Eclipse MAT-ot csak az index betöltéséhez.
Igen, használja az Eclipse MAT-ot (Memory Analyzer Tool) — egy ingyenes eszközt a .hprof elemzéséhez. Támogatja a dominator tree-t, a path to GC roots-t, a dumpok összehasonlítását és az automatikus szivárgáskeresést a Leak Suspects Report segítségével.
Maga a dump — igen, mert a dump készítése felfüggeszti az összes szálat (stop-the-world). Dump nélkül — nem. Készítsen dumprot ellenőrzött körülmények között (tesztkörnyezet, CI), ne élesben.
Összefoglalás
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.
Olvassa el is