🌳 Dominator Tree & Retained Size - Measuring the True Cost of Memory Leaks

 

Introduction

In Part 4, we saw how Shark parses heap dumps and generates leak traces. But not all leaks are equal. A retained Activity holding onto dozens of Views is far more dangerous than a single leaked Bitmap.

To prioritize, Shark calculates retained size using a dominator tree algorithm. This lets developers see not just what is leaking, but how much memory is being wasted.

🧩 What is a Dominator Tree?

A dominator tree is a graph structure used in memory analysis:

  • Each node represents an object in the heap.
  • A node dominates another if every path from a GC root to that object passes through the dominator.
  • The retained size of a node is the total memory that would be freed if that node were garbage collected.

Think of it like a family tree of memory ownership: if the parent dies, all children go with it.

⚙️ Shark’s Retained Size Calculation

1. Build Heap Graph

val heapGraph = Hprof.openHeapGraph(heapDumpFile)

2. Construct Dominator Tree

val dominatorTree = DominatorTree(heapGraph)

3. Compute Retained Size

val retainedSize = dominatorTree.retainedSize(leakingActivity)
println("Leaking Activity retains $retainedSize bytes")

📊 Diagram: Dominator Tree Flow

GC RootsHeap GraphDominator TreeRetained SizeLeak Prioritization

🧑‍💻 Example: Leaking Activity

Suppose a destroyed Activity is still retained:

  • It dominates its Views, Adapters, and child Fragments.
  • Retained size might be 5 MB.
  • LeakCanary reports:
┬───
Retained size: 5 MB

├─ com.example.LeakyActivity
Leaking: YES

This tells you fixing this leak frees 5 MB instantly.

🚨 Why This Matters

  • Prioritisation: Focus on leaks with the largest retained size.
  • Impact awareness: Not all leaks are catastrophic — dominator trees show which ones are.
  • Advocacy tool: Helps you explain to teams and stakeholders why fixing leaks improves performance.

🔮 Coming Next

In Part 6, we’ll explore Common Android Leak Patterns — real‑world examples like Handler leaks, static Context references, and InputMethodManager traps, with code and diagrams.

Comments