Heap Dump: what it is, heap analysis and memory leak elimination

Author: IT Sectr Published: 2026-05-07 Reading time: 10 min

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 snapshot of the entire application's dynamic memory with information about each object and the references between them.
  • Android Studio Memory Profiler allows capturing heap dumps in real time for Java and Kotlin applications.
  • Xcode Instruments provides the Allocations tool for creating and analyzing heap dumps on iOS/macOS.
  • Shallow and retained size are key metrics: shallow is the size of the object itself, retained is the object's size plus all objects it holds onto.
  • Analyzing a heap dump involves searching the dominator tree, biggest retained objects, and shortest paths to GC roots.

What is a heap dump and why do you need it

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.

When a heap dump is needed

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.

Heap dump in Android Studio: capture and analysis

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.

kotlin
// 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
    }
}

Dominator tree analysis in Android Studio

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.

Heap dump in Xcode Instruments: Allocations and Leaks

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.

swift
// 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.

swift
// Fix — weak reference to self
onComplete = { [weak self] data in
    guard let self else { return }
    self.process(data)
}

Shallow size, retained size, and dominator tree

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.

MetricDescriptionExample
Shallow sizeSize of the object itself in bytesBitmap (100×100) = 40,016 B
Retained sizeShallow size + everything it holdsActivity with View Tree = 2–5 MB
Deep sizeRetained size + nested objects from other graphsScrollView 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.

Memory leak analysis via heap dump

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.

Path to GC Roots

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.

kotlin
// 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>>()
}

Comparing two heap dumps

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.

Best practices for reducing memory consumption

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.

Memory profiling during development

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.

groovy
// 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

What is the difference between shallow size and retained size?

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.

How to take a heap dump on a physical Android device?

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.

Why can a heap dump be huge (500 MB+)?

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.

Can I analyze a heap dump without Android Studio?

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.

Does a heap dump affect app performance?

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

  • Heap Dump is a complete snapshot of the application heap with information about each object and relationships between them.
  • Android Studio Memory Profiler and Xcode Instruments Allocations are the primary dump capture tools.
  • Shallow size is the size of the object itself; retained size is the object's size including its entire dependency subgraph.
  • Dominator tree shows objects that control the most memory.
  • Path to GC Roots is the chain of strong references keeping an object from garbage collection.
  • Comparing two heap dumps (before/after an action) is the most reliable method for detecting leaks.
  • Automating heap dump capture and analysis in CI prevents memory regressions during development.

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.

Discuss the project

Read also