LeakCanary: Detect all memory leaks!

A memory leak detection library for Android and Java.

Square Engineering
May 8, 2015 · 4 min read

Written by Pierre-Yves Ricau.

Heads up, we’ve moved! If you’d like to continue keeping up with the latest technical content from Square please visit us at our new home https://developer.squareup.com/blog

java.lang.OutOfMemoryError
at android.graphics.Bitmap.nativeCreate(Bitmap.java:-2)
at android.graphics.Bitmap.createBitmap(Bitmap.java:689)
at com.squareup.ui.SignView.createSignatureBitmap(SignView.java:121)

Nobody likes OutOfMemoryError crashes

In Square Register, we draw the customer’s signature on a bitmap cache. This bitmap is the size of the device’s screen, and we had a significant number of out of memory (OOM) crashes when creating it.

Image for post
Image for post

We tried a few approaches, none of which solved the issue:

  • Use Bitmap.Config.ALPHA_8 (a signature doesn’t need color).
  • Catch OutOfMemoryError, trigger the GC and retry a few times (inspired from GCUtils).
  • We didn’t think of allocating bitmaps off the Java heap. Lucky for us, Frescodidn’t exist yet.

We were looking at it the wrong way

The bitmap size was not a problem. When the memory is almost full, an OOM can happen anywhere. It tends to happen more often in places where you create big objects, like bitmaps. The OOM is a symptom of a deeper problem: memory leaks.

What is a memory leak?

Some objects have a limited lifetime. When their job is done, they are expected to be garbage collected. If a chain of references holds an object in memory after the end of its expected lifetime, this creates a memory leak. When these leaks accumulate, the app runs out of memory.

For instance, after Activity.onDestroy() is called, the activity, its view hierarchy and their associated bitmaps should all be garbage collectable. If a thread running in the background holds a reference to the activity, then the corresponding memory cannot be reclaimed. This eventually leads to an OutOfMemoryError crash.

Hunting memory leaks

Hunting memory leaks is a manual process, well described in Raizlabs’ Wrangling Dalvik series.

Here are the key steps:

  1. Learn about OutOfMemoryError crashes via Bugsnag, Crashlytics, or the Developer Console.
  2. Attempt to reproduce the problem. You might need to buy, borrow, or steal the specific device that suffered the crash. (Not all devices will exhibit all leaks!) You also need to figure out what navigation sequence triggers the leak, possibly by brute force.
  3. Dump the heap when the OOM occurs (here’s how).
  4. Poke around the heap dump with MAT or YourKit and find an object that should have been garbage collected.
  5. Compute the shortest strong reference path from that object to the GC roots.
  6. Figure out which reference in the path should not exist, and fix the memory leak.

What if a library could do all this before you even get to an OOM, and let you focus on fixing the memory leak?

Introducing LeakCanary

LeakCanary is an Open Source Java library to detect memory leaks in your debug builds.

Let’s look at a cat example:

class Cat {
}
class Box {
Cat hiddenCat;
}
class Docker {
static Box container;
}
// ...Box box = new Box();
Cat schrodingerCat = new Cat();
box.hiddenCat = schrodingerCat;
Docker.container = box;

You create a RefWatcher instance and give it an object to watch:

// We expect schrodingerCat to be gone soon (or not), let's watch it.
refWatcher.watch(schrodingerCat);

When the leak is detected, you automatically get a nice leak trace:

* GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance

We know you’re busy writing features, so we made it very easy to setup. With just one line of code, LeakCanary will automatically detect activity leaks:

public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}

You get a notification and a nice display out of the box:

Image for post
Image for post

Conclusion

After enabling LeakCanary, we discovered and fixed many memory leaks in our app. We even found a few leaks in the Android SDK.

The results are amazing. We now have 94% fewer crashes from OOM errors.

Image for post
Image for post

If you want to eliminate OOM crashes, install LeakCanary now!

Square Corner Blog

Buying and selling sound like simple things - and they…

Square Engineering

Written by

The official account for @Square Engineering.

Square Corner Blog

Buying and selling sound like simple things - and they should be. Somewhere along the way, they got complicated. At Square, we're working hard to make commerce easy for everyone.

Square Engineering

Written by

The official account for @Square Engineering.

Square Corner Blog

Buying and selling sound like simple things - and they should be. Somewhere along the way, they got complicated. At Square, we're working hard to make commerce easy for everyone.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store