Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Leak Canary

I am currently experiencing an OutOfMemoryError in my apps. I have tried to debug using MAT, but it is still too hard to find the leak in a few activities. Then I found LeakCanary, which seems simpler and easier to use, however I could not find any beginner step by step guide on using Leak Canary, even on Google. I have installed LeakCanary through the dependencies in my build.gradle, and this is what I got so far:

ExampleApplication.java

public class ExampleApplication extends Application {      public static RefWatcher getRefWatcher(Context context) {         ExampleApplication application = (ExampleApplication) context.getApplicationContext();         return application.refWatcher;     }      private RefWatcher refWatcher;      @Override     public void onCreate() {         super.onCreate();         refWatcher = LeakCanary.install(this);     }      final class KeyedWeakReference extends WeakReference<Object> {         public final String key;         public final String name;          KeyedWeakReference(Object referent, String key, String name,                        ReferenceQueue<Object> referenceQueue) {             super(checkNotNull(referent, "referent"), checkNotNull(referenceQueue, "referenceQueue"));             this.key = checkNotNull(key, "key");             this.name = checkNotNull(name, "name");         }     }      public void watch(Object watchedReference, String referenceName) {         checkNotNull(watchedReference, "watchReference");         checkNotNull(referenceName, "referenceName");         if(debuggerControl.isDebuggerAttached()) {             return;         }         final long watchStartNanoTime = System.nanoTime();         String key = UUID.randomUUID().toString();         retainedKeys.add(key);         final KeyedWeakReference reference =             new KeyedWeakReference(watchedReference, key, referenceName, queue);         watchExecutor.execute()      } } 

Let's say I have an Activity where I want LeakCanary to watch an object

SampleActivity.java

public class SampleActivity extends Activity implements View.OnClickListener {     ImageView level001, level002;          @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.choose_level);          level001 = (ImageView) findViewById(R.id.level001);         level002 = (ImageView) findViewById(R.id.level002);          // Do all kinds of functions         // How do I use LeakCanary to watch these objects?      } } 

Now how do I use LeakCanary to see which object is causing the memory leak?

like image 991
Charas Avatar asked Nov 11 '15 15:11

Charas


People also ask

How does leak Canary work?

LeakCanary hooks into the Android lifecycle to automatically detect when activities and fragments are destroyed and should be garbage collected. These destroyed objects are passed to an ObjectWatcher , which holds weak references to them.

What is leak canary?

LeakCanary is a memory leak detection library for Android. LeakCanary's knowledge of the internals of the Android Framework gives it a unique ability to narrow down the cause of each leak, helping developers dramatically reduce Application Not Responding freezes and OutOfMemoryError crashes.

Is LeakCanary open source?

LeakCanary is an open-source memory leak detection library developed by Square organization.


2 Answers

The nice thing about leak canary is how automated it works. By default, it already "watches" for activities that are not being properly GCed. So out of the box, if any activity is leaking you should receive the notification.

On my project I've added an extra method on the Application like this:

public class ExampleApplication extends Application {     public static ExampleApplication instance;     private RefWatcher refWatcher;      @Override     public void onCreate() {         super.onCreate();         instance = this;         refWatcher = LeakCanary.install(this);     }      public void mustDie(Object object) {         if (refWatcher != null) {             refWatcher.watch(object);         }     } } 

so the important stuff with garbage collection and memory leak and canary is to know when stuff should be collected and ask that item to be watched.

For for example we're using a "base fragment" with the following code:

@Override public void onDestroy() {     super.onDestroy();     ExampleApplication.instance.mustDie(this); } 

this way LeakCanary is trying to check if any fragment is leaking memory.

So for you to further implement on your app, you could/should on tasks or instances that you know it should be garbage collected but you think it might not be, and you're not sure where, you can call that too: ExampleApplication.instance.mustDie(object);

and then you MUST run the application and rotate the device and force the leak to happen, so leak canary can grab/analyse the stack trace and give you valuable information on how to fix it.

I hope it helps.

like image 55
Budius Avatar answered Sep 24 '22 14:09

Budius


Posting this answer because all other answers are no longer needed and there's a better way to find leaks on your app using Leak Canary 2.

Just add below dependency to your gradle. No more code needed.

debugImplementation 'com.squareup.leakcananry:leakcanary-android:2.7' 
like image 27
Prakash Avatar answered Sep 22 '22 14:09

Prakash