Posts

📢 LeakCanary Reporting & Advocacy - Turning Leak Traces into Stories

Image
  Introduction LeakCanary doesn’t just detect leaks — it reports them in a way that developers can act on. But the real power lies in how you, as an engineer and advocate, interpret those reports and communicate their impact. This is the difference between “I fixed a leak” and “I helped my team understand why memory leaks degrade UX and how to prevent them.” That’s advocacy. 🧩 Anatomy of a Leak Report LeakCanary surfaces leaks via: In‑app notifications (quick feedback loop). Detailed LeakTrace UI (reference chains). Exported reports (for CI/CD integration). Example LeakTrace ┬─── │ GC Root: System class │ ├─ android.view.inputmethod.InputMethodManager │ Leaking: NO │ ↓ InputMethodManager.mLastSrvView ├─ com.example.LeakyActivity │ Leaking: YES (Activity was destroyed) │ Retained size: 5 MB This tells you: The GC root holding the leak. The chain of references. Whether the object is leaking. The retained size impact. 📊 Diagram: Leak Report Flow Heap...

LeakCanary ObjectWatcher Deep Dive - The Silent Guardian of Memory

Image
  Introduction In Part 1, we saw how LeakCanary detects leaks at a high level. But the real magic begins with ObjectWatcher  — the component that quietly observes destroyed objects and decides whether they’re truly gone or suspiciously retained. Understanding ObjectWatcher is crucial if you want to debug leaks beyond surface level and explain them with authority. 🧩 What is ObjectWatcher? ObjectWatcher is a core utility inside LeakCanary that: Tracks destroyed objects (Activities, Fragments, Views, ViewModels). Holds them via weak references . Periodically checks if they’ve been garbage collected. Flags them as retained if they’re still alive after GC. Think of it as a security guard : once an object leaves the building (destroyed), ObjectWatcher ensures it doesn’t sneak back in. ⚙️ How ObjectWatcher Works 1. Watching Objects objectWatcher.watch( destroyedActivity, "Activity was destroyed but not GC'd" ) LeakCanary calls watch() whenever a lifecycle event signa...

🚨 Why Memory Leaks Matter in Android (and How LeakCanary Saves You)

Image
  Every Android engineer has faced the dreaded OutOfMemoryError . It doesn’t happen on day one, but weeks after release, when users have navigated through dozens of screens. Suddenly, the app slows down, GC thrashes, and boom — crash. The silent culprit? Memory leaks. This post kicks off a series where we’ll dissect LeakCanary and its engine Shark , showing you not just how to use them, but how they work internally. By the end, you’ll be able to debug leaks like a pro — and explain them like an advocate. 🧠 What is a Memory Leak? A memory leak occurs when an object that should be garbage collected is still retained in memory because something is holding a reference to it. Example: Leaking Activity class LeakyActivity : AppCompatActivity () { companion object { // ❌ Static reference keeps Activity alive var instance: LeakyActivity? = null } override fun onCreate (savedInstanceState: Bundle ?) { super .onCreate(savedInstanceState) ...

LeakCanary Internals — A Complete Guide for Android Engineers

Image
Introduction Over the past few weeks, we’ve gone on a journey through LeakCanary and its engine Shark — from the basics of memory leaks to the deepest internals of heap analysis. This wrap‑up post ties everything together, giving you a single reference point for the entire series. If you’re serious about Android performance, debugging, and advocacy, this is your roadmap. 📚 The Series in Review 1. Why Memory Leaks Matter Defined leaks and their dangers. Showed a leaking Activity example. Explained why leaks silently degrade performance. 2. ObjectWatcher Deep Dive Explored how LeakCanary tracks destroyed objects. Weak references + ReferenceQueue checks. Manual watching for custom objects. 3. Heap Dumping Explaine How LeakCanary freezes the app and writes .hprof . Trade‑offs of heap dumping. Why it’s worth it for accuracy. 4. Shark Heap Analysis Parsing .hprof into HeapGraph. Shortest path finder from GC roots. LeakTrace reports with actionable insights. 5. Dominator Tree & Retai...

Fat AAR: Bundling Transitive Dependencies for Zero-Config Android SDK Consumers

Image
  Your SDK has 12 transitive dependencies. Your consumer’s build.gradle shouldn’t know about any of them. Why This Problem Is Uniquely Hard in KMP If you’re building a Kotlin Multiplatform SDK, you’re already dealing with complexity that traditional Android libraries never face. Your commonMain code compiles to both JVM bytecode (Android) and native binaries (iOS). On iOS, the XCFramework is self-contained - all Kotlin/Native dependencies compile into a single static binary. There's no "dependency resolution" on the Swift side. But on Android? You’re back in Gradle-land. Your KMP module produces a standard .aar , and every api() or implementation() dependency in your build.gradle.kts becomes a transitive edge in the consumer's dependency graph. The irony: the platform with the better tooling has the worse distribution story. This asymmetry is what makes Fat AAR essential for KMP SDK teams. iOS gets zero-config by default (static XCFramework). Android needs us to b...