Posts

🗂️ Heap Dumping Explained - LeakCanary's Bold Move

Image
  Introduction In Part 2, we explored ObjectWatcher , the silent guardian that tracks destroyed objects. But what happens when ObjectWatcher suspects foul play? LeakCanary doesn’t just shrug — it goes nuclear: it dumps the heap . Heap dumping is the most dramatic step in LeakCanary’s workflow. It freezes your app, writes a snapshot of memory to disk, and hands it over to Shark for analysis. Let’s break down why, how, and what happens next. ⚙️ What is a Heap Dump? A heap dump is a binary snapshot of the JVM heap at a given moment. It contains: All objects currently in memory. Their classes and fields. References between objects. GC roots (entry points into the object graph). Think of it as a crime scene photo : everything in memory is captured exactly as it is. 🧑‍💻 Triggering a Heap Dump LeakCanary triggers a heap dump when retained objects exceed a threshold: 5 retained objects when the app is visible. 1 retained object when the app is backgrounded. Code Example HeapDumpTrigg...

🦈 Shark Heap Analysis - LeakCanary's Detective at Work

Image
  Introduction In Part 3, we saw how LeakCanary boldly freezes your app to capture a heap dump . But a .hprof file is just raw binary data — unreadable to humans. Enter Shark , LeakCanary’s analysis engine. Shark parses the dump, builds a navigable object graph, and uncovers the exact reference chains that keep your objects alive. This is where leaks stop being mysterious and start becoming actionable. ⚙️ Shark’s Workflow 1. Parsing the Heap Dump Shark uses Shark Hprof (built on Okio) to stream through .hprof records efficiently. val heapGraph = Hprof.openHeapGraph(heapDumpFile) Converts raw data into a HeapGraph . HeapGraph exposes classes, objects, fields, and references. 2. Building the Heap Graph HeapGraph lets you query memory like a database: val activityClass = heapGraph.findClassByName( "com.example.LeakyActivity" ) val instances = activityClass.instances You can traverse references between objects. This graph is the foundation for leak detection. 3. Findi...

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

Image
  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 = Dom...

🧩 Common Android Leak Patterns - Real‑World Traps LeakCanary Catches

Image
  Introduction In Part 5, we explored how Shark quantifies leaks with dominator trees and retained size . But theory only gets us so far. Let’s look at the real‑world leak patterns that plague Android apps — the ones LeakCanary was built to catch. These examples are code‑driven, diagram‑supported, and exactly the kind of content that sparks discussion in the Android community. 1. Static Context Reference object ContextHolder { var context: Context? = null } ❌ Holding a Context in a static field prevents GC. If it’s an Activity context, the entire UI tree leaks. Diagram: GC Root → ContextHolder → Activity → Views 2. Anonymous Inner Class Leak class LeakyActivity : AppCompatActivity () { private val runnable = Runnable { // references outer Activity } } Inner classes hold implicit references to their outer class. If posted to a long‑lived thread, the Activity leaks. 3. Handler Leak class LeakyActivity : AppCompatActivity () { private val hand...

⚡ Integrating LeakCanary in CI/CD - Automating Leak Detection

Image
  Introduction So far, we’ve explored how LeakCanary detects leaks, analyzes heap dumps with Shark, and categorizes them. But in real teams, leaks often slip through because developers only check them locally. The next step is automation : integrating LeakCanary into your CI/CD pipeline so leaks are caught before release. This transforms LeakCanary from a developer tool into a team safeguard . 🛠️ Configuring LeakCanary for CI LeakCanary is designed for debug builds , but you can configure it to export leak reports for CI. Gradle Setup dependencies { debugImplementation "com.squareup.leakcanary:leakcanary-android:2.12" } Exporting Leak Reports LeakCanary stores reports in: /storage/emulated/0/Download/leakcanary/ You can configure CI to collect these reports after instrumentation tests. 🧑‍💻 Example: CI Script # Run instrumentation tests ./gradlew connectedDebugAndroidTest # Collect LeakCanary reports adb pull /storage/emulated/0/Download/leakcanary ./ci-reports/leaks ...