所谓内存分析,其实是为了防止APP造成的内存泄露问题,常用的内存分析软件包括MAT,Android Studio自带软件,这两个软件给我们调试带来很大的便利,后面我们会陆续介绍,今天我们来说说我用的最多的工具 LeakCanary。

准备工作


LeakCanary是有Squary开发的,用于分析内存泄露的App,对,没错,就是一款App,超级好用,只需要完成下面两步,就可以帮我们分析内存问题

  1. 添加依赖
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'
 }
  1. 在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提示我们内存泄露了!

android 内存分析角度 安卓内存分析app_内存泄露

简单说明下,这个流程从下往上看,大概意思是,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为我们内存分析创造了非常便利的条件,有兴趣的童鞋都应该去试试~