PY edited this page Jul 21, 2018 · 42 revisions

Why should I use LeakCanary?

A memory leak is a programming error that causes your application to keep a reference to an object that is no longer needed. As a result, the memory allocated for that object cannot be reclaimed, eventually leading to an OutOfMemoryError crash.

For instance, an Android activity instance is no longer needed after its onDestroy() method is called, and storing a reference to that activity in a static field would prevent it from being garbage collected.

LeakCanary identifies an object that is longer needed and finds the chain of references that prevents it from being garbage collected.

When we first enabled LeakCanary in the Square Point Of Sale app, we were able to find and fix several leaks and reduced the OutOfMemoryError crash rates by 94%.

How does it work?

  1. RefWatcher.watch() creates a KeyedWeakReference to the watched object.
  2. Later, in a background thread, it checks if the reference has been cleared and if not it triggers a GC.
  3. If the reference is still not cleared, it then dumps the heap into a .hprof file stored on the file system.
  4. HeapAnalyzerService is started in a separate process and HeapAnalyzer parses the heap dump using HAHA.
  5. HeapAnalyzer finds the KeyedWeakReference in the heap dump thanks to a unique reference key and locates the leaking reference.
  6. HeapAnalyzer computes the shortest strong reference path to the GC Roots to determine if there is a leak, and then builds the chain of references causing the leak.
  7. The result is passed back to DisplayLeakService in the app process, and the leak notification is shown.

How do I fix a memory leak?

To fix a memory leak, you need to look at that chain and find which reference is causing the leak, i.e. which reference should have been cleared at the time of the leak. LeakCanary highlights with a red underline wave the references that are the possible causes of the leak.

If you cannot figure out an issue in your code, please do not file an issue. Instead, create a Stack Overflow question (using the leakcanary tag).

How do I customize LeakCanary to my needs?

See Customizing LeakCanary.

Where can I learn more?

How do I copy the leak trace?

You can see the leak trace in Logcat:

In com.example.leakcanary:1.0:1 com.example.leakcanary.MainActivity has leaked:
* GC ROOT thread java.lang.Thread.<Java Local> (named 'AsyncTask #1')
* references com.example.leakcanary.MainActivity$3.this$0 (anonymous class extends android.os.AsyncTask)
* leaks com.example.leakcanary.MainActivity instance

* Reference Key: e71f3bf5-d786-4145-8539-584afaecad1d
* Device: Genymotion generic Google Nexus 6 - 5.1.0 - API 22 - 1440x2560 vbox86p
* Android Version: 5.1 API: 22
* Durations: watch=5086ms, gc=110ms, heap dump=435ms, analysis=2086ms

You can also share the leak trace and the heap dump file from the action bar menu.

Can a leak be caused by the Android SDK?

Yes. There are a number of known memory leaks that have been fixed over time in AOSP as well as in manufacturer implementations. When such a leak occurs, there is little you can do as an app developer to fix it. For that reason, LeakCanary has a built-in list of known Android leaks to ignore: AndroidExcludedRefs.java.

If you find a new one, please create an issue and follow these steps:

  1. Provide the entire leak trace information (reference key, device, etc), and use backticks (`) for formatting.
  2. Read the AOSP source for that version of Android, and try to figure out why it happens. You can easily navigate through SDK versions android/platform_frameworks_base.
  3. Check if it happens on the latest version of Android, and otherwise use blame to find when it was fixed.
  4. If it's still happening, build a simple repro case
  5. File an issue on b.android.com with the leak trace and the repro case
  6. Create a PR in LeakCanary to update AndroidExcludedRefs.java. Optional: if you find a hack to clear that leak on previous versions of Android, feel free to document it.

This is especially important for new releases of Android. You have the opportunity to help detect new memory leaks early on, which benefits the entire Android community.

How can I dig beyond the leak trace?

Sometimes the leak trace isn't enough and you need to dig into the heap dump with MAT or YourKit. Here's how you can find the leaking instance in the heap dump:

  1. Look for all instances of com.squareup.leakcanary.KeyedWeakReference
  2. For each of these, look at the key field.
  3. Find the KeyedWeakReference that has a key field equal to the reference key reported by LeakCanary.
  4. The referent field of that KeyedWeakReference is your leaking object.
  5. From then on, the matter is in your hands. A good start is to look at the shortest path to GC Roots (excluding weak references).

How do I disable LeakCanary in tests?

To disable LeakCanary in unit tests, add the following to your build.gradle:

// Ensure the no-op dependency is always used in JVM tests.
configurations.all { config ->
  if (config.name.contains('UnitTest')) {
    config.resolutionStrategy.eachDependency { details ->
      if (details.requested.group == 'com.squareup.leakcanary' && details.requested.name == 'leakcanary-android') {
        details.useTarget(group: details.requested.group, name: 'leakcanary-android-no-op', version: details.requested.version)
      }
    }
  }
}

If you want to also disable leak detection in instrumentation tests, add || config.name.contains('AndroidTest') to the if check above.

How do I fix build errors?

  • if leakcanary-android is not in the list of external libraries in Android Studio, but leakcanary-analyzer and leakcanary-watcher are there: try doing a Clean Build. If it's still a problem, try building from the command line.
  • error: package com.squareup.leakcanary does not exist: if you have other build types than debug and release, you need to add a specific dependency for those too (xxxCompile).

How many methods does LeakCanary add?

The short answer is 9, or 0 if you use ProGuard.

LeakCanary should only be used in debug builds, and should be disabled in release builds. We provide a special empty dependency for your release builds: leakcanary-android-no-op.

The full version of LeakCanary is bigger and should never ship in your release builds.

How do I use the SNAPSHOT version?

Update your dependencies to the latest SNAPSHOT (see build.gradle):

 dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.7-SNAPSHOT'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.7-SNAPSHOT'
 }

Add Sonatype's snapshots repository:

  repositories {
    mavenCentral()
    maven {
      url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
  }

Status of the snapshot build: Build Status

How can I be notified of new releases?

You can watch releases on Bintray.

Who's behind LeakCanary?

LeakCanary was created and open sourced by @pyricau, and is currently maintained by @jrodbx, @JakeWharton and @pyricau.

Why is it called LeakCanary?

The name LeakCanary is a reference to the expression canary in a coal mine, because LeakCanary is a sentinel used to detect risks by providing advance warning of a danger. Props to @edenman for suggesting it!

Who made the logo?

@pyricau quickly made the first version of the logo. It was based on cliparts from Android Asset Studio, mixed with the selection from a photo of a Canary. The exclamation mark means danger, the shield stands for protection, and the bird, well, is a canary. @romainguy turned the ugly logo into a nice vector asset.

Instant Run can trigger invalid leaks

Enabling Android Studio's Instant Run feature can cause LeakCanary to report invalid memory leaks. See issue #37967114 on the Android Issue Tracker.

I know I have a leak. Why doesn't the notification show?

Are you attached to a debugger? LeakCanary ignores leak detection when debugging to avoid false positives.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.