Overview
The memory leak can be a headache to detect and to resolve, small memory leaks can be hidden and may be seen after a long usage of the application and hunting memory leaks is not a simple task.In this tutorial we will create a leaked application and we will use the LeakCanary library to detect the memory leak.
Step 1: add the LeakCanary dependency to the application
Modify the app/build.gradle to add the LeakCanary dependency as follows:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dependencies { | |
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' | |
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' | |
} |
Step 2: Extend and configure the Application class
We need to call LeakCanary.install in onCreate method:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package anaware.leakcanarysample; | |
import android.app.Application; | |
import android.content.Context; | |
import com.squareup.leakcanary.LeakCanary; | |
import com.squareup.leakcanary.RefWatcher; | |
public class MyApplication extends Application { | |
private RefWatcher refWatcher; | |
public static RefWatcher getRefWatcher(Context context) { | |
MyApplication application = (MyApplication) context.getApplicationContext(); | |
return application.refWatcher; | |
} | |
@Override | |
public void onCreate() { | |
super.onCreate(); | |
refWatcher = LeakCanary.install(this); | |
} | |
} |
Step 3: Create a leaked activity
For this we will create a singleton class that saves the context:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package anaware.leakcanarysample; | |
import android.content.Context; | |
public class SingletonSavesContext { | |
private Context context; | |
private static SingletonSavesContext instance; | |
public Context getContext() { | |
return context; | |
} | |
public void setContext(Context context) { | |
this.context = context; | |
} | |
public static SingletonSavesContext getInstance() { | |
if (instance == null) { | |
instance = new SingletonSavesContext(); | |
} | |
return instance; | |
} | |
} |
Then, the main activity (leaked one), will use the singleton and then we'll go to a new activity:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package anaware.leakcanarysample; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.os.AsyncTask; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import com.squareup.leakcanary.RefWatcher; | |
public class LeakedActivity extends AppCompatActivity { | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
new MyAsyncTask().execute(this); | |
} | |
@Override | |
public void onDestroy() { | |
super.onDestroy(); | |
RefWatcher refWatcher = MyApplication.getRefWatcher(this); | |
refWatcher.watch(this); | |
} | |
public class MyAsyncTask extends AsyncTask<Object, String, String> { | |
private Context context; | |
@Override | |
protected String doInBackground(Object... params) { | |
context = (Context)params[0]; | |
// Invoke the leak! | |
SingletonSavesContext.getInstance().setContext(context); | |
// Simulate long running task | |
try { | |
Thread.sleep(3000); | |
} catch (InterruptedException e) { | |
} | |
return "result"; | |
} | |
@Override | |
protected void onPostExecute(String s) { | |
super.onPostExecute(s); | |
Intent newActivity = new Intent(context, AnotherActivity.class); | |
startActivity(newActivity); | |
} | |
} | |
} |
Then, in the new activity we'll call System.gc to force the garbage collector in order to accelerate the analysis.
Step 4: Retrieve the analysis result
A nice notification can be shown:The result can be retrieved from logcat:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14211-16753/anaware.leakcanarysample D/LeakCanary: In anaware.leakcanarysample:1.0:1. | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * anaware.leakcanarysample.LeakedActivity has leaked: | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * GC ROOT static anaware.leakcanarysample.SingletonSavesContext.instance | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * references anaware.leakcanarysample.SingletonSavesContext.context | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * leaks anaware.leakcanarysample.LeakedActivity instance | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * Reference Key: 226ffd5e-902c-4202-8508-2e268616e2ae | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * Device: samsung samsung GT-I9305 m3xx | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * Android Version: 4.4.4 API: 19 LeakCanary: 1.3.1 | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * Durations: watch=5007ms, gc=120ms, heap dump=617ms, analysis=13070ms | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * Details: | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * Class anaware.leakcanarysample.SingletonSavesContext | |
14211-16753/anaware.leakcanarysample D/LeakCanary: | static $staticOverhead = byte[] [id=0x42548e79;length=24;size=40] | |
14211-16753/anaware.leakcanarysample D/LeakCanary: | static instance = anaware.leakcanarysample.SingletonSavesContext [id=0x42548fb8] | |
14211-16753/anaware.leakcanarysample D/LeakCanary: * Instance of anaware.leakcanarysample.SingletonSavesContext | |
14211-16753/anaware.leakcanarysample D/LeakCanary: | static $staticOverhead = byte[] [id=0x42548e79;length=24;size=40] | |
14211-16753/anaware.leakcanarysample D/LeakCanary: | static instance = anaware.leakcanarysample.SingletonSavesContext [id=0x42548fb8] | |
14211-16753/anaware.leakcanarysample D/LeakCanary: | context = anaware.leakcanarysample.LeakedActivity [id=0x424ebbe8] |
Source code
Complete source code of the sample can be found in Github.Complete documentation of LeakCanary can be found in the following links:
https://corner.squareup.com/2015/05/leak-canary.html
https://github.com/square/leakcanary
Komentar
Posting Komentar