Heap Dump (heap dump) is a snapshot of an application's dynamic memory containing complete information about all live objects: their classes, sizes, mutual references, and reachability from GC roots. Heap Dump is the primary tool for analyzing memory leaks and optimizing resource consumption. According to Android Developers, heap dump analysis can detect up to 95% of memory leaks, including cyclic references, forgotten listeners, and unreleased static references.
Key Takeaways
Heap dump is a complete dump of the virtual machine heap — the memory area where all dynamically created objects reside. In Java and Kotlin this is the Dalvik/ART heap on Android, in Swift and Objective-C it is the ARC-managed heap on iOS. A heap dump captures every object, its class, size, fields, references to other objects, and reachability flags from GC roots (stack variables, static fields, JNI references).
The main purpose of a heap dump is memory leak detection. A leak occurs when an application continues holding references to objects that are no longer needed, preventing garbage collection (or ARC deallocation). Typical causes: event listeners not unregistered when an activity is destroyed; singletons holding references to context; closures capturing self; static collections where data is added without removal. A heap dump provides an accurate picture: which objects are “alive”, which are unnecessary, and who exactly is referencing them.
According to Google I/O, more than 60% of Android app crash reports are related to OutOfMemoryError, and in 80% of cases the root cause is a memory leak detectable via heap dump. For iOS apps the situation is similar: leaks due to retain cycles are one of the most common causes of crashes, identified through the Allocations instrument in Xcode.
A heap dump should be performed when the following symptoms appear: the app consumes memory linearly during repeated actions (navigating back and forth between screens); after closing a screen, memory does not return to the baseline level; OutOfMemoryError or iOS memory warning occurs; the app terminates due to exceeding the memory limit (EXC_RESOURCE_RESOURCE on iOS). Regular heap dump collection is part of the engineering culture protocol in major mobile projects such as Instagram and Spotify.
Android Studio provides Memory Profiler — a built-in tool for capturing heap dumps in real time. Access it via View → Tool Windows → Profiler. After launching the app, select the session, go to the Memory tab and click Dump Java Heap. Android Studio pauses the app, performs an ART heap dump, and loads the result for analysis. The dump file is in .hprof format — the HPROF standard compatible with most memory analyzers.
After loading the dump, Android Studio displays an object table with columns: Allocations (instance count), Native Size (memory outside the ART heap), Shallow Size (object's own memory), Retained Size (object's memory including its entire subgraph). Filtering by class name, sorting by retained size, and searching by packages allow you to quickly find problematic areas.
// Typical leak — a listener not unregistered in 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()
// ❌ Missing sensorManager.unregisterListener(listener)
// → Activity won't be GC'd, heap dump will show the leak
}
}
The Dominator Tree tab shows objects that hold the largest amount of memory. If you remove an object from the dominator tree, all the memory it holds becomes available for garbage collection. This is a key tool: instead of scanning thousands of objects, you focus on 10–20 that control 80–90% of memory. According to Google, dominator tree analysis is the most effective way to find a leak point, reducing analysis time from hours to minutes.
Xcode Instruments provides two tools for working with heap dumps: Allocations — captures heap dumps with real-time consumption graphs; Leaks — automatically finds leaks through retain cycle analysis. Allocations displays all objects in the heap, their size, number of allocations and deallocations. The difference between the number of allocations and deallocations for a specific class indicates a potential leak.
Capturing a heap dump in Allocations is done with the Snapshot Memory button — the tool pauses the app and takes a full dump. After that, standard views are available: object list by class, call tree for each object, and a report generator. Unlike Android Studio, Xcode does not use .hprof but stores data in its own .trace format compatible with Instruments.
// Typical iOS leak — retain cycle through a closure
class NetworkManager {
var onComplete: ((Data) -> Void)?
func startRequest() {
// ❌ Closure captures self — retain cycle
onComplete = { data in
self.process(data)
}
}
func process(_ data: Data) {}
}
The Leaks instrument automatically detects retain cycles and leaks through reference graph analysis. It marks leaking objects with a purple icon and shows the path to the root (GC root). To fix a retain cycle, simply add [weak self] or [unowned self] in the closure capture. Regular Leaks instrument runs are a mandatory CI pipeline step in teams using Swift for iOS development.
// Fix — weak reference to self
onComplete = { [weak self] data in
guard let self else { return }
self.process(data)
}
To properly analyze a heap dump, you need to understand three key metrics. Shallow size is the memory occupied directly by the object: its fields, header, and alignment. For a typical Java/Kotlin object, shallow size is 16–40 bytes. Retained size is the shallow size of the object plus the total shallow size of all objects that are only reachable through this object (i.e., would become garbage if it were removed). Retained size shows the object's real impact on memory consumption.
| Metric | Description | Example |
|---|---|---|
| Shallow size | Size of the object itself in bytes | Bitmap (100×100) = 40,016 B |
| Retained size | Shallow size + everything it holds | Activity with View Tree = 2–5 MB |
| Deep size | Retained size + nested objects from other graphs | ScrollView with adapter = 10–50 MB |
Dominator tree is a structure where each object references its “dominator” — the object that controls its reachability. If the dominator is removed, all objects in its subtree become garbage. Dominator tree analysis is the fastest way to find which object holds the most memory. According to Eclipse MAT (Memory Analyzer Tool), 90% of leaks are detected by reviewing the top-20 dominator tree in 5 minutes.
The process of analyzing a leak via heap dump consists of several steps. Step 1: perform the action that should free memory (close the screen, finish the operation). Step 2: trigger GC (System.gc() in Android, forced snapshot in Xcode) and take a heap dump. Step 3: find objects that should have been destroyed (e.g., an Activity instance after finish). Step 4: for the suspicious object, run Path to GC Roots — the chain of references keeping the object alive. The last reference in the chain is the leak cause.
The Path to GC Roots function is available in Android Studio Profiler, Eclipse MAT, and Xcode Instruments. It shows the shortest chain of references from a GC root to the problematic object. By excluding weak and soft references, you get only strong ones — those that actually prevent garbage collection. According to Square Engineering, 70% of leaks in Android apps are caused by just two patterns: static references to Activity or Context, and registered but not unregistered listeners.
// Example of a leak through a static reference
object AppCache {
private val cache = mutableMapOf<String, Any>()
fun storeActivityReference(activity: Activity) {
cache["current_activity"] = activity // ❌ Leak!
}
}
// Fix: weak reference
object AppCacheFixed {
private val cache = mutableMapOf<String, WeakReference<Any>>()
}
The comparison mode technique is one of the most effective leak detection methods. Take a heap dump before and after a repeated action (e.g., navigating to a screen and back five times). Compare the instance counts of key classes: if the number of Activity instances grew even though all activities were closed — it is a leak. Android Studio and Eclipse MAT support automatic dump comparison with highlighted differences. According to Google, dump comparison reveals leaks invisible in a single analysis by accumulating the effect.
Based on heap dump analysis in real projects, proven memory optimization practices have been developed. Use WeakReference for caches, callbacks, and context references in long-lived objects. Unregister listeners in onPause/onDestroy for Android and deinit for iOS. Avoid large static collections — if necessary, use LruCache with a size limit. Optimize Bitmaps: load images with the correct inSampleSize, use Glide or Picasso with disk cache.
Include regular heap dump capture in your CI pipeline. Set up a task that runs instrumented UI tests, performs key user scenarios, and compares the heap dump against a baseline. If retained size grows by more than 5% from baseline, the build is flagged as a regression. This approach is practiced at Airbnb, Uber, and other companies with high quality standards. According to Uber Engineering, implementing automatic heap dump analysis in CI reduced memory-related bugs by 70% in one quarter.
// Example Gradle task for automatic heap dump in CI
task profileMemory(type: Exec) {
commandLine 'adb', 'shell',
'am start -n com.example/.MainActivity'
// Waiting for load
doLast {
exec { commandLine 'adb', 'shell',
'am broadcast -a com.example.DUMP_HEAP' }
}
}
Frequently Asked Questions
Shallow size is the size of the object itself (fields + header). Retained size is the size of the object plus all objects that would become garbage if it were removed. Retained size is the main indicator of an object's impact on memory consumption.
Through Android Studio Profiler, select the device and process, click Dump Java Heap. Alternatively, via the command line: adb shell am dumpheap PID /sdcard/dump.hprof, then adb pull.
A heap dump includes all live objects. If the app uses caches, Bitmaps, or processes large data, the dump can reach hundreds of megabytes. Filter by classes or use Eclipse MAT to load only the index.
Yes, use Eclipse MAT (Memory Analyzer Tool) — a free tool for analyzing .hprof files. It supports dominator tree, path to GC roots, dump comparison, and automatic leak detection via Leak Suspects Report.
The dump itself — yes, because dump collection pauses all threads (stop-the-world). Without a dump — no. Take dumps in controlled environments (test bench, CI), not in production.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also