Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external...
Transcript of Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external...
1
Leak Canary Intro
Jennifer McGee
What is Leak Canary?
Leak Canary
•Open source library written by Square’s
Pierre-Yves (PY) Ricau
•Library which attempts to automatically
detect and report memory leaks in android
Leak Cannary
Memory Leaks in Java
3
Objects Reachable
from GC Roots
GC Roots
GC Overview
4
GC Root GC Root
Object
ObjectObject
Object
ObjectObject
Not Reachable from GC Root
GC Roots
GC Overview
5
GC Root GC Root
Object
ObjectObject
Object
ObjectObject
Can be garbage collected
Leak Cannary
How Leak Canary Works
6
Basic Idea
1) Identify objects you are worried about leaking 2) When they are destroyed keep a week reference 3) Wait 4) If not garbage collected notify of possible memory leak
Android Memory Leaks
7
Key Classes
Leak Canary
8
What does RefWatcher Coordinate Leak Canary
9
How Do We Guess when activities Should have been garbage collected?
Android Memory Leaks
10
RecyclerView
11
Q: How can we guess when fragments should have been garbage collected?
A: Extend Fragment
public abstract class BaseFragment extends Fragment {
@Override public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
Leak Cannary
Leak Canary Leak Demo
12
Leak Cannary
13
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); View button = findViewById(R.id.async_task); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startAsyncTask(); } }); } void startAsyncTask() { // This async task is an anonymous class and therefore has a hidden reference to the outer // class MainActivity. If the activity gets destroyed before the task finishes (e.g. rotation), // the activity instance will leak. new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { // Do some slow work in background SystemClock.sleep(20000); return null; } }.execute(); }}
Activity that Will Leak
Leak Cannary
14
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: In com.example.leakcanary:1.0:1.
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * com.example.leakcanary.MainActivity has leaked:
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * GC ROOT thread java.lang.Thread.<Java Local> (named 'AsyncTask #2’)
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * references com.example.leakcanary.MainActivity$2.this$0 (anonymous subclass of android.os.AsyncTask)
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * leaks com.example.leakcanary.MainActivity instance
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * Retaining: 260KB.
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * Reference Key: f856c32b-53ad-4f31-bb5b-a51c2208943c
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * Device: Genymotion generic Samsung Galaxy S4 - 4.4.4 - API 19 - 1080x1920 vbox86p
02-21 17:52:58.124 31708-13109/com.example.leakcanary D/LeakCanary: * Android Version: 4.4.4 API: 19 LeakCanary: 1.4-SNAPSHOT
What a Leak Log Looks Like
What has Leaked
GC Root
How much Memory
Reference Key
Android Memory Leaks
How to Setup Leak Canary in your App
15
RecyclerView
16
Basic Leak Canary SetupIn your Gradle File:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
}
In your Application Class:
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
Android Memory Leaks
What about Memory Leaks you Can’t Fix?
17
LeakCanary
18
What Does LeakCanary.install(this) do? Lets look at the source
public static RefWatcher install(Application application) {
return install(application, DisplayLeakService.class,
AndroidExcludedRefs.createAppDefaults().build());
}
public static RefWatcher install(Application application,
Class<? extends AbstractAnalysisResultService> listenerServiceClass,
ExcludedRefs excludedRefs) {
…
Look there it has an
overwritten constructor!
We
pass
in
Excl
uded
Ref
s O
bjec
t
LeakCanary
19
How To Add 3rd Party Exclusions
ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults()
.instanceField("com.example.third.party.TheirClassOne", "fieldName")
.instanceField("com.example.third.party.TheirClassTwo", "fieldName")
.build();
LeakCanary.install(application, DisplayLeakService.class, excludedRefs);
Add in the additional exclusions
here
LeakCanary
20
Excluded Refs Builder Interface
public interface Builder { BuilderWithParams instanceField(String className, String fieldName); BuilderWithParams staticField(String className, String fieldName); BuilderWithParams thread(String threadName); BuilderWithParams clazz(String className); BuilderWithParams rootClass(String rootSuperClassName); ExcludedRefs build();}
LeakCanary
21
Known Android SDK Leaks are in AndroidExcludedRefs.java
Parts of an Excluded Leak:
Name (Manufacturer and SDK Range){ @Override void add(ExcludedRefs.Builder excluded) {
excluded.type of field <instance,static,root class, clazz>(“full.path.ClassToIgnore”, “field that was leaked")
.reason(“comment reason for the leak”); } } }
https://github.com/square/leakcanary/blob/master/leakcanary-android/src/main/java/com/squareup/leakcanary/AndroidExcludedRefs.java
Android Memory Leaks
Leak Canary Gotcha’s
22
Leak Cannary
23
Leak Canary on 6.0 and latter phones
Leak Cannary
24
Here is what you see in the Log 02-21 19:37:13.544 15173-15188/com.example.leakcanary D/LeakCanary: Could not attempt cleanup, leak storage not writable.02-21 19:37:24.592 15173-15189/com.example.leakcanary D/LeakCanary: Could not write to leak storage to dump heap.
Cause:
LeakCannary needs to write out heap dumps to external storage, so it needs the read and write external permissions, but on 6.0 this must be requested at run time
Fix:
use 1.4-beta1 or latter
enable storage permission when notification pops up notification
Leak Canary on 6.0 and latter phones
Android Memory Leaks
Fun with OQL
25
Leak Cannary
26
To find the referenced object in HPROF
To find your leaked object in the hprof file SELECT * FROM INSTANCEOF com.squareup.leakcanary.KeyedWeakReference a WHERE a.key = <Reference Key from Log>
SELECT * FROM INSTANCEOF android.app.Activity a WHERE a.mDestroyed = true
If you don’t have LeakCanary but do have hprof
27
28
Questions?
Special Thanks to Bottle Rocket Studios for providing meeting space and allowing me to share this material which is a simplified version of material presentation at a weekly code and tell .
More Resources https://realm.io/news/droidcon-ricau-memory-leaks-leakcanary/
https://github.com/square/leakcanary