所谓内存分析,其实是为了防止APP造成的内存泄露问题,常用的内存分析软件包括MAT,Android Studio自带软件,这两个软件给我们调试带来很大的便利,后面我们会陆续介绍,今天我们来说说我用的最多的工具 LeakCanary。
准备工作
LeakCanary是有Squary开发的,用于分析内存泄露的App,对,没错,就是一款App,超级好用,只需要完成下面两步,就可以帮我们分析内存问题
- 添加依赖
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
}
- 在Application里面安装
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
}
}
案例说明
我们用GitHub上的demo来说说这个软件都好用~
完成上面两步准备,我们开始写我们的MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startAsyncTask
}
void startAsyncTask() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// Do some slow work in background
SystemClock.sleep(10000);
return null;
}
}.execute();
}
}
代码很简单,编译完成后,打开,按返回键退出之后,等待10s,LeakCanary提示我们内存泄露了!
简单说明下,这个流程从下往上看,大概意思是,MainActivity无法被回收,因为被Thread引用了,所以我们可以知道AsyncTask启动的线程导致内存泄露。
为什么会有内存泄露呢?
相信很多童鞋都知道,这是因为,我们这里使用了匿名内部类AsyncTask,对当前Activity都有一个隐式引用。如果Activity在销毁的时候,AsyncTask内部的任务还未完成, 那么将导致Activity的内存资源无法回收,造成内存泄漏。修改的方法也很简单,就是使用静态内部类!来看看我们的修改:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TestAsyncTask sTestAsyncTask = new TestAsyncTask();
sTestAsyncTask.execute();
}
private static class TestAsyncTask extends AsyncTask<Void,Void,Void>{
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(10000);
return null;
}
}
}
上面代码中,自定义了静态的内部类TestAsyncTask ,实现了AsyncTask,然后在使用的时候实例化它。运行后,返回键退出,等待10s,没有内存泄露,Prefect~
顺便说一下,为啥我们需要使用静态内部类? ,这是因为:当一个变量被声明为static时,他就变成了类变量,而不是对象变量,这样就不会受对象的声明周期影响,静态变量只有在我们完全退出APP(进程被kill),才会销毁
写在后面
有许多地方都会导致内存泄露,在我们项目里,比较常见的就是线程的不正确引用,或者单例引用,LeakCanary为我们内存分析创造了非常便利的条件,有兴趣的童鞋都应该去试试~