Android 内存泄漏相关

Posted by ijays on January 31, 2017

Android 内存泄漏相关

在了解内存泄漏之前,先来了解下Java 的引用类型

  • 强引用:即默认的引用类型,例如

    StringBuffer sb = new StringBuffer();
    

    就是sb 持有了StringBuffer的强引用类型。

  • 弱引用:即WeakReference,其指向的对象只有在GC执行时才会被回收。

  • 软引用:即SoftReference,其指向的对象只有在内存不足的时候进行回收。

  • 虚引用:即phantomReference,与ReferenceQueue 结合,用作记录该引用指向的对象已被销毁。

在Android 中内存泄漏的场景很多,一般情况有:

  1. 长期持有了Activity(Context)。
  2. 忘记注销监听器或者观察者。
  3. 非静态内部类持有外部类的引用。

针对以上情况的一些解决方案:

  1. 尽量避免使用Activity 的Context,多使用Application 的Context,其生命周期为App的生命周期。
  2. 手动解除不必要的强引用关系。
  3. 使用弱引用或者软引用替换强引用关系。
  4. 将生命周期长的非静态内部类替换成静态内部类。

检测内存泄漏的方式主要有MAT,集成在了Android Studio 中,以及Square 开发的LeakCanary。

下面以Handler 的使用为例。

由于非静态内部类会持有外部类的引用,所以在Activity 中创建非静态的自定义Handler 可能会导致内存泄漏。

public class MainActivity extends Activity {

    private final Handler mLeakyHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // ...
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mLeakyHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                // ...
            }
        }, 1000 * 60 * 10);

        finish();
    }
}

如果自定义的 Handler 中没有使用到外部类,就可以直接静态化避免不必要的引用外部类:

static final Handler mLeakyHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // ...
    }
}

如果该自定义的 Handler 需要使用外部的 Activity 引用,可以使用弱引用来避免内存泄露:

private static class MyHandler extends Handler {
    private final WeakReference<MainActivity> mActivityReference;

    public MyHandler(MainActivity activity) {
            mActivityReference = new WeakReference<MainActivity>(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        MainActivity activity = mActivityReference.get();
        if (activity != null) {
            // 使用弱引用一定要注意检查为空
        }
    }
}