Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external...

28
1 Leak Canary Intro Jennifer McGee

Transcript of Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external...

Page 1: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

1

Leak Canary Intro

Jennifer McGee

Page 2: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 3: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Leak Cannary

Memory Leaks in Java

3

Page 4: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Objects Reachable

from GC Roots

GC Roots

GC Overview

4

GC Root GC Root

Object

ObjectObject

Object

ObjectObject

Page 5: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Not Reachable from GC Root

GC Roots

GC Overview

5

GC Root GC Root

Object

ObjectObject

Object

ObjectObject

Can be garbage collected

Page 6: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Leak Cannary

How Leak Canary Works

6

Page 7: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 8: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Key Classes

Leak Canary

8

Page 9: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

What does RefWatcher Coordinate Leak Canary

9

Page 10: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

How Do We Guess when activities Should have been garbage collected?

Android Memory Leaks

10

Page 11: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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);

}

}

Page 12: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Leak Cannary

Leak Canary Leak Demo

12

Page 13: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 14: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 15: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Android Memory Leaks

How to Setup Leak Canary in your App

15

Page 16: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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);

}

}

Page 17: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Android Memory Leaks

What about Memory Leaks you Can’t Fix?

17

Page 18: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 19: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 20: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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();}

Page 21: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 22: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Android Memory Leaks

Leak Canary Gotcha’s

22

Page 23: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Leak Cannary

23

Leak Canary on 6.0 and latter phones

Page 24: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 25: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

Android Memory Leaks

Fun with OQL

25

Page 26: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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

Page 27: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

27

Page 28: Leak Canary Intro Jennifer McGee - Meetupfiles.meetup.com/1791179/LeakCanaryIntro.pdfwrite external permissions, but on 6.0 this must be requested at run time Fix: use 1.4-beta1 or

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