Memory Leaks on Android

36
Memory Leaks SOFTWARE ENGINEER | AUTHOR | CONSULTANT Omri Erez @innovationMaze | https://medium.com/@OomriErez WHAT YOU DON’T KNOW WILL DRIVE YOU CRAZY

Transcript of Memory Leaks on Android

Page 1: Memory Leaks on Android

Memory Leaks

SOFTWARE ENGINEER | AUTHOR | CONSULTANTOmri Erez

@innovationMaze | https://medium.com/@OomriErez

WHAT YOU DON’T KNOW WILL DRIVE YOU CRAZY

Page 2: Memory Leaks on Android

About Me

Page 3: Memory Leaks on Android

Memory Leak

A scenario in which our application persistently retains an object’s memory, even after it is not needed anymore.

Page 4: Memory Leaks on Android

The Garbage Collector

Source: https://flic.kr/p/pWwnZf

Page 5: Memory Leaks on Android

Component Life Cycle

Activity Life Cycle

App Life Cycle

Service Life Cycle

Page 6: Memory Leaks on Android

References TreeGC

Root

O2

O3 O4

Page 7: Memory Leaks on Android

Source: https://flic.kr/p/q2TrC7

Page 8: Memory Leaks on Android

GC Roots

Static variables

& functions

References on a stack

JNI references

& objects

Page 9: Memory Leaks on Android

A Memory LeakGC

Root

O2

O3

O4

Page 10: Memory Leaks on Android

Source: https://flic.kr/p/52jkCJ

Page 11: Memory Leaks on Android

Source: https://flic.kr/p/6H4wxP

Page 12: Memory Leaks on Android

What you don’t know WILL drive you crazy

Page 13: Memory Leaks on Android

Scenario 1

Page 14: Memory Leaks on Android

private static View mLeakingView; private byte[] mBytes=new byte[1000000]; @Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity); mLeakingView = findViewById(R.id.mainView); mLeakingView.setOnClickListener(view -> finish()); MyStringHelper.getInstance().setActivity(this); Log.d(TAG,MyStringHelper.getInstance().getString(R.string.app_name)); }

Static References

Page 15: Memory Leaks on Android

Static Referencespublic final class MyStringHelper { private final static MyStringHelper INSTANCE = new MyStringHelper(); private Context mActivityContext; public static MyStringHelper getInstance() {return INSTANCE;} public void setActivity(Context context) {mActivityContext=context;} public String getString(int id) { return mActivityContext.getString(id); } private MyStringHelper() { if (INSTANCE != null) { throw new IllegalStateException("Already instantiated"); } }}

Page 16: Memory Leaks on Android

The Source of the Leak

•Static reference to a view

•Static instance of MyStringHelper

Their lifecycle is longer than the activity lifecycle

Page 17: Memory Leaks on Android

A Memory Leak

GC RootmLeakingView

Activity

GC RootMyStringHelper

Page 18: Memory Leaks on Android

Solution?

Page 19: Memory Leaks on Android

Solution :|

@Overrideprotected void onDestroy() { mLeakingView=null; MyStringHelper.getInstance()

.setActivityContext(null); super.onDestroy(); }

Page 20: Memory Leaks on Android

Solution :)

•Avoid static references especially to Android components like activities, services and views

•Use Application context instead of the Activity context

Page 21: Memory Leaks on Android

Scenario 2

Page 22: Memory Leaks on Android

Anonymous Classes//Anonymous classprivate final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { } }; @Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity); mView.setOnClickListener(view -> finish()); mLeakyHandler.sendEmptyMessageDelayed(MESSAGE_ID,20000);}

Page 23: Memory Leaks on Android

A Memory Leak

Looper ActivitymLeakyHandler

Page 24: Memory Leaks on Android

Source: https://flic.kr/p/6H4wxP

Page 25: Memory Leaks on Android

Solution :|

@Overrideprotected void onDestroy() { mLeakyHandler.removeMessages(MESSAGE_ID); super.onDestroy(); }

Page 26: Memory Leaks on Android

Solution :)

•When using the Handler class, make sure its static

Page 27: Memory Leaks on Android

Scenario 3

Page 28: Memory Leaks on Android

Non Static Inner Classes

private class MyRunnable implements Runnable { @Override public void run() { Log.d(TAG, "I am running in activity:" + InnerClassLeakingActivity.this.getComponentName()); } }

Page 29: Memory Leaks on Android

Solution :)

•Avoid non-static inner classes

•Use WeakReference if needed

Page 30: Memory Leaks on Android

Solution :)private static class MyRunnable implements Runnable{ WeakReference<InnerClassLeakingActivity> mWeakActivity; public MyRunnable(InnerClassLeakingActivity activity) { this.mWeakActivity = new WeakReference<>(activity); } @Override public void run() { final InnerClassLeakingActivity activity=mWeakActivity.get(); if (activity!=null) Log.d(TAG, String.format("I am running in activity:%s" ,activity.getComponentName()));

}}

Page 31: Memory Leaks on Android
Page 32: Memory Leaks on Android

Tools for Automatic Detection

Page 33: Memory Leaks on Android

StrictMode

•Here to help find developers mistakes and bring it to our attention

•Very easy to use

Page 34: Memory Leaks on Android

StrictMode :)

if (BuildConfig.DEBUG) { StrictMode.VmPolicy vmPolicy=new StrictMode.VmPolicy.Builder() .detectActivityLeaks()

.detectLeakedSqlLiteObjects() .detectLeakedClosableObjects() .penaltyLog() .build(); StrictMode.setVmPolicy(vmPolicy); }

Page 35: Memory Leaks on Android

Leak Canary

•Created by Pierre-Yves Ricau (Square Inc)

•Very easy to use

•Tracks objects for memory leaks

Page 36: Memory Leaks on Android

Thank you!

Q & A@innovationMaze | [email protected]

https://goo.gl/qtnq0S