Heap Dump (heap-dump) — en ögonblicksbild av applikationens dynamiska minne som innehåller fullständig information om alla levande objekt: deras klasser, storlekar, ömsesidiga referenser och tillgänglighet från rotnoder (GC roots). Heap Dump är det främsta verktyget för att analysera minnesläckor och optimera resursförbrukning. Enligt Android Developers kan analys av heap-dumpar upptäcka upp till 95% av minnesläckor, inklusive cykliska referenser, bortglömda listeners och inte frigjorda statiska referenser.
Huvudpunkter
Heap dump är en fullständig dump av den virtuella maskinens heap — det minnesområde där alla dynamiskt skapade objekt placeras. I Java och Kotlin är detta Dalvik/ART på Android, i Swift och Objective-C — ARC-hanterad heap på iOS. En heap dump registrerar varje objekt, dess klass, storlek, fält, referenser till andra objekt och flaggor för tillgänglighet från GC roots (stackvariabler, statiska fält, JNI-referenser).
Huvudsyftet med en heap dump är att upptäcka minnesläckor. En läcka uppstår när applikationen fortsätter att hålla referenser till objekt som inte längre behövs, vilket förhindrar dem från att samlas in av garbage collectorn (eller frigöras via ARC). Typiska orsaker: event-lyssnare som inte avregistrerats vid förstöring av en activity; singletons med referenser till context; closures som fångar self; statiska samlingar där data läggs till utan borttagning. En heap dump ger en exakt bild: vilka objekt är „levande", vilka är överflödiga och vem refererar exakt till dem.
Enligt Google I/O är över 60% av crash-rapporterna för Android-applikationer relaterade till OutOfMemoryError, och i 80% av fallen är grundorsaken en minnesläcka som kan upptäckas via heap dump. För iOS-applikationer är situationen liknande: läckor orsakade av retain cycles är en av de vanligaste orsakerna till krascher som upptäcks via Allocations-instrumentet i Xcode.
En heap dump bör utföras vid följande symptom: applikationen förbrukar minne linjärt vid upprepade handlingar (navigering fram och tillbaka mellan skärmar); efter att en skärm har avslutats återgår inte minnet till den ursprungliga nivån; OutOfMemoryError eller memory warning-meddelanden uppträder på iOS; applikationen avslutas på grund av att minnesgränsen överskrids (EXC_RESOURCE_RESOURCE på iOS). Regelbunden insamling av heap-dumpar är en del av ingenjörskulturens protokoll i stora mobilprojekt som Instagram och Spotify.
Android Studio tillhandahåller Memory Profiler — ett inbyggt verktyg för att fånga heap-dumpar i realtid. Tillgängligt via View → Tool Windows → Profiler. Efter att ha startat applikationen väljer du session, går till fliken Memory och klickar på Dump Java Heap. Android Studio pausar applikationen, utför en dump av ART-heapen och laddar resultatet för analys. Dumpfilen har formatet .hprof — HPROF-standarden som är kompatibel med de flesta minnesanalysatorer.
Efter att dumpen har laddats visar Android Studio en tabell med objekt med kolumner: Allocations (antal instanser), Native Size (minne utanför ART-heapen), Shallow Size (objektets eget minne), Retained Size (objektets minne med hela subgrafen). Filtrering efter klassnamn, sortering efter retained size och sökning efter paket gör det möjligt att snabbt hitta problemområden.
// Typisk läcka — listener inte avregistrerad i 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) missades
// → Activity samlas inte in av GC, heap dump visar läckan
}
}
Fliken Dominator Tree visar objekt som håller den största mängden minne. Om ett objekt tas bort från dominator tree blir allt minne som det håller tillgängligt för insamling. Detta är ett nyckelverktyg: istället för att granska tusentals objekt fokuserar du på 10-20 som kontrollerar 80-90% av minnet. Enligt Google är dominator tree-analys det mest effektiva sättet att hitta en läckpunkt, vilket minskar analystiden från timmar till minuter.
Xcode Instruments tillhandahåller två verktyg för att arbeta med heap-dumpar: Allocations — fånga heap-dump med en realtidsgraf över förbrukning; Leaks — automatisk sökning efter läckor genom analys av retain cycles. Allocations visar alla objekt i heapen, deras storlek, antal skapanden (allocations) och frigöranden (deallocations). Skillnaden mellan antal skapanden och frigöranden för en specifik klass indikerar en potentiell läcka.
Att fånga en heap dump i Allocations görs med knappen Snapshot Memory — verktyget pausar applikationen och tar en fullständig dump. Därefter är standardvyerna tillgängliga: en lista över objekt efter klass, ett anropsträd (call tree) för varje objekt och en rapportgenerator. Till skillnad från Android Studio använder Xcode inte .hprof, utan lagrar data i sitt eget format .trace, kompatibelt med Instruments.
// Typisk iOS-läcka — retain cycle via closure
class NetworkManager {
var onComplete: ((Data) -> Void)?
func startRequest() {
// ❌ Closure fångar self — retain cycle
onComplete = { data in
self.process(data)
}
}
func process(_ data: Data) {}
}
Leaks-instrumentet upptäcker automatiskt retain cycles och läckor genom analys av referensgrafen. Det markerar läckande objekt med en lila ikon och visar vägen till roten (GC root). För att åtgärda en retain cycle räcker det att lägga till [weak self] eller [unowned self] i closuren. Regelbunden körning av Leaks-instrumentet är ett obligatoriskt CI-steg i team som använder Swift för iOS-utveckling.
// Åtgärd — svag referens till self
onComplete = { [weak self] data in
guard let self else { return }
self.process(data)
}
För korrekt analys av en heap dump måste du förstå tre nyckelmått. Shallow size — mängden minne som direkt upptas av objektet: dess fält, header och justering. För ett typiskt Java/Kotlin-objekt är shallow size 16-40 byte. Retained size — objektets shallow size plus den totala shallow size för alla objekt som endast är tillgängliga via detta objekt (dvs blir skräp vid borttagning). Det är retained size som visar objektets verkliga påverkan på minnesförbrukningen.
| Mått | Beskrivning | Exempel |
|---|---|---|
| Shallow size | Objektets egen storlek i byte | Bitmap (100×100) = 40 016 B |
| Retained size | Shallow size + allt det håller | Activity med View Tree = 2-5 MB |
| Deep size | Retained size + nästlade objekt från andra grafer | ScrollView med adapter = 10-50 MB |
Dominator tree — en struktur där varje objekt refererar till sin „dominator" — objektet som kontrollerar dess tillgänglighet. Om dominatorn tas bort blir alla objekt i dess underträd skräp. Analys av dominator tree är det snabbaste sättet att hitta objektet som håller mest minne. Enligt Eclipse MAT (Memory Analyzer Tool) upptäcks 90% av läckorna genom att granska top-20 dominator tree inom 5 minuter.
Processen för läckanalys via heap dump består av flera steg. Steg 1: utför handlingen som borde frigöra minnet (stäng skärmen, slutför operationen). Steg 2: anropa GC (System.gc() i Android, tvingad snapshot i Xcode) och gör en heap dump. Steg 3: hitta objekt som borde ha förstörts (t.ex. en Activity-instans efter finish). Steg 4: för det misstänkta objektet, kör Path to GC Roots — kedjan av referenser som håller objektet vid liv. Den sista referensen i kedjan är orsaken till läckan.
Funktionen Path to GC Roots finns i Android Studio Profiler, Eclipse MAT och Xcode Instruments. Den visar den kortaste kedjan av referenser från GC root till problemobjektet. Genom att utesluta svaga (weak) och mjuka (soft) referenser får du endast starka (strong) referenser — de som faktiskt förhindrar insamling. Enligt statistik från Square Engineering orsakas 70% av läckorna i Android-applikationer av endast två mönster: statiska referenser till Activity eller Context och registrerade men inte avregistrerade listeners.
// Exempel på läcka via statisk referens
object AppCache {
private val cache = mutableMapOf<String, Any>()
fun storeActivityReference(activity: Activity) {
cache["current_activity"] = activity // ❌ Läcka!
}
}
// Åtgärd: svag referens
object AppCacheFixed {
private val cache = mutableMapOf<String, WeakReference<Any>>()
}
Tekniken comparison mode — en av de mest effektiva metoderna för att hitta läckor. Gör en heap dump före och efter en upprepad handling (t.ex. fem navigeringar till en skärm och tillbaka). Jämför antalet instanser av nyckelklasser: om antalet Activity har ökat, trots att alla aktiviteter har stängts — är det en läcka. Android Studio och Eclipse MAT stöder automatisk jämförelse av dumpar med markering av skillnader. Enligt Google gör jämförelse av dumpar det möjligt att hitta läckor som är osynliga vid en engångsanalys tack vare ackumulering av effekten.
Baserat på analys av heap-dumpar i verkliga projekt har beprövade optimeringsmetoder utvecklats. Använd WeakReference för cacheminnen, återanrop och referenser till context i långlivade objekt. Avregistrera listeners i onPause/onDestroy för Android och deinit för iOS. Undvik stora statiska samlingar — om de är nödvändiga, använd LruCache med storleksbegränsning. Optimera Bitmaps: ladda bilder med korrekt inSampleSize, använd Glide eller Picasso med diskcache.
Inkludera regelbunden insamling av heap-dumpar i CI. Konfigurera en uppgift som kör instrumenterade UI-tester, utför viktiga användarscenarier och jämför heap-dumpen med en baseline. Om retained size har ökat med mer än 5% från baseline markeras bygget som en regression. Detta tillvägagångssätt praktiseras på Airbnb, Uber och andra företag med höga kvalitetskrav. Enligt Uber Engineering minskade införandet av automatisk heap dump-analys i CI antalet minnesrelaterade buggar med 70% på en kvartal.
// Exempel på Gradle-uppgift för automatisk heap dump i CI
task profileMemory(type: Exec) {
commandLine 'adb', 'shell',
'am start -n com.example/.MainActivity'
// Väntar på laddning
doLast {
exec { commandLine 'adb', 'shell',
'am broadcast -a com.example.DUMP_HEAP' }
}
}
Vanliga frågor
Shallow size — objektets egen storlek (fält + header). Retained size — objektets storlek plus alla objekt som blir skräp vid borttagning. Retained size är den främsta indikatorn på objektets påverkan på minnesförbrukningen.
Via Android Studio Profiler väljer du enhet och process, klickar på Dump Java Heap. Alternativt — via kommandoraden: adb shell am dumpheap PID /sdcard/dump.hprof, sedan adb pull.
En heap dump omfattar alla levande objekt. Om applikationen använder cacheminnen, Bitmaps eller bearbetar stora datamängder kan dumpen nå flera hundra megabyte. Filtrera efter klass eller använd Eclipse MAT för att bara ladda indexet.
Ja, använd Eclipse MAT (Memory Analyzer Tool) — ett gratis verktyg för att analysera .hprof. Det stöder dominator tree, path to GC roots, dumpjämförelse och automatisk läcksökning via Leak Suspects Report.
Själva dumpen — ja, eftersom dumpningen pausar alla trådar (stop-the-world). Utan dump — nej. Gör dumpen under kontrollerade förhållanden (testmiljö, CI), inte i produktion.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också