🌳 Dominator Tree & Retained Size - Measuring the True Cost of Memory Leaks
Dominator Tree and Retained Size — Measuring the True Cost of Android Memory Leaks
Learn how Shark uses dominator trees and retained size to measure leak impact, prioritize fixes, and explain the real cost of retained objects in Android apps.
In the previous part of this series, we saw how Shark parses heap dumps and generates leak traces. But one important question still remains: which leaks should you fix first?
Not all memory leaks are equally dangerous. A destroyed Activity retaining an entire view hierarchy can be far more expensive than a small isolated object. That is why Shark uses dominator trees and retained size to estimate impact, not just existence.
Table of Contents
- 1. Why Not All Leaks Are Equal
- 2. What Is a Dominator Tree?
- 3. What Is Retained Size?
- 4. How Shark Uses Dominator Trees
- 5. Example: Leaking Activity with Retained Size
- 6. Why This Matters in Real Apps
- 7. Analyze LeakCanary Reports Faster with LeakLens
- 8. What to Read Next
1. Why Not All Leaks Are Equal
Leak detection tells you that something is being retained. Impact analysis tells you whether that leak is small, moderate, or serious.
- A tiny object leak may be noisy but not urgent.
- A leaked Activity may retain Views, adapters, child Fragments, drawables, and other large object graphs.
- A high retained size usually means more wasted memory and more pressure on app stability.
This is where retained size becomes more useful than raw leak count. It helps you prioritize based on cost rather than just occurrence.
2. What Is a Dominator Tree?
A dominator tree is a graph structure used in memory analysis. In simple terms, one object dominates another object if every path from a GC root to that object passes through the dominator.
That means the dominated object cannot stay alive independently. If the dominator is collected, the dominated objects can usually be collected too.
- Each node represents an object in the heap.
- A parent object may dominate many children in the object graph.
- This structure helps analysis tools estimate memory ownership and cleanup impact.
A simple mental model is a memory ownership tree: if the parent goes away, its dominated subtree can go away with it.
3. What Is Retained Size?
Retained size is the total amount of memory that would be freed if a particular object were garbage collected.
This includes not only the memory used by the object itself, but also the memory used by objects that are kept alive only because of it.
- Shallow size: memory used by the object itself.
- Retained size: shallow size plus the dominated memory graph that depends on it.
This distinction matters because the most dangerous leaks are usually not the biggest individual objects, but the objects retaining large subgraphs.
4. How Shark Uses Dominator Trees
Shark uses dominator tree analysis after parsing the heap dump. Once it builds the heap graph, it can estimate which objects dominate others and how much memory would be recovered if a leaking object were fixed.
val heapGraph = Hprof.openHeapGraph(heapDumpFile)
val dominatorTree = DominatorTree(heapGraph)
val retainedSize = dominatorTree.retainedSize(leakingActivity)
High-level analysis flow:
GC Roots → Heap Graph → Dominator Tree → Retained Size → Leak Prioritization
This is what turns a heap dump from a static snapshot into a prioritization tool.
5. Example: Leaking Activity with Retained Size
Suppose a destroyed Activity is still retained in memory. That Activity may dominate many related objects:
- its view hierarchy,
- adapters and listeners,
- child Fragments,
- drawables, caches, and other UI-linked objects.
In that case, LeakCanary and Shark may report something like:
Retained size: 5 MB
com.example.LeakyActivity
Leaking: YES
This does not just mean the Activity is leaking. It means fixing that one root retention problem could free roughly 5 MB of memory immediately.
6. Why This Matters in Real Apps
Dominator trees and retained size matter because they improve engineering judgment.
- Better prioritization: fix large-impact leaks before minor noise.
- Clearer performance reasoning: retained size helps explain memory pressure more concretely.
- Stronger advocacy: it is easier to justify a fix when you can show how much memory is being wasted.
- Smarter triage: teams can separate “interesting” leaks from “urgent” leaks.
In mature Android teams, this kind of prioritization is what turns memory debugging from reactive cleanup into deliberate performance engineering.
7. Analyze LeakCanary Reports Faster with LeakLens
Retained size and dominator trees are powerful, but large reports can still be difficult to interpret quickly. LeakLens helps by analyzing LeakCanary reports, explaining retention paths, and suggesting likely fixes directly inside Android Studio.
It is especially useful when you want to move faster from “this leak retains 5 MB” to “this is the most likely root cause and fix.”
8. What to Read Next
This article explains how Shark measures impact. To continue through the full LeakCanary internals series, read the related posts below:
- Why Memory Leaks Matter in Android
- LeakCanary ObjectWatcher Deep Dive
- Heap Dumping Explained
- Shark Heap Analysis
- Common Android Leak Patterns
- Integrating LeakCanary in CI/CD
- LeakCanary Reporting & Advocacy
- LeakCanary Internals: Complete Guide for Android Engineers
FAQ
What is a dominator tree in memory analysis?
A dominator tree shows which objects control the reachability of other objects from GC roots, making it easier to estimate memory ownership and impact.
What is retained size in LeakCanary or Shark?
Retained size is the total memory that would be freed if a leaking object were garbage collected, including the objects it keeps alive.
Why is retained size more useful than leak count?
Leak count tells you how many suspicious objects exist, but retained size helps prioritize which leaks are actually expensive and urgent.
This guide is part of the Android Quality Suite.

Comments
Post a Comment