使用LeakCanary进行内存溢出检测

    1.问题:平时由于工期比较紧,写代码的时候可能想的不是那么周全,大多情况下追求的是功能是否实现,却忽略了性能问题,比如说算法、数据结构、内存消耗等,今天主要分享内存泄漏的分析与解决方案
       内存泄漏:所谓内存泄漏就是指本该回收的内存还驻留在内存中

           1.1 Android内存回收机制:Android虚拟机采用的是根节点搜索算法枚举根节点判定是否是垃圾,虚拟机会从GC Roots  开始遍历,如果一个节点找不到一条到达GC Roots的路线,也就是说没有和GC Roots相连,那么就证明该引用无效,可以被回收,内存泄漏就是存在一些不好的调用导致一些无用的对象和GC Roots相连,无法回收。
            1.2 Andorid中内存泄漏大致原因
                    1.2.1 static变量引起的内存泄漏:因为static变量的生命周期是在类加载开始到类加载结束,也就是说static变量是在程序进程死亡时才释放,如果在static变量中引用了Activity,那么这个Activity由于被引用,便会和static变量的生命周期一样,一直无法释放,造成内存泄漏
                    ** 解决方案:在Activity被静态引用时,使用getApplicationContext,因为Application的生命周期是从程序开始到程序结束,和static变量的生命周期一样;如果在某些Dialog或者一些单例里面用到了Activity,可以在这些类里面写一个release方法用于释放Activity引用,比如给Dialog设置OnDismissListener()在里面释放Activity引用
                    1.2.2 线程造成的内存泄漏:例如在Activity里面线程执行时间很长,即使Activity退出该线程仍然会执行,因为线程或者Runnable是内部类,因此持有外部类(Activity)的实例,从而导致Activity无法释放
                    ** 解决方案:1)合理安排线程执行的时间,控制线程在Activity结束前结束(在run方法里面设置代码执行开关,即flag,一般长时间执行的线程都是循环执行一些操作)
                                        2)将内部类改为静态内部类,并使用弱引用WeakReference来保存Activity实例,因为弱引用只要GC发现了就会回收它,因此可尽快回收(静态内部类不依赖外部类)
                 1.2.3 资源未被及时关闭造成的内存泄漏:比如数据库Cursor没有及时close,读写文件的时候IO流没有及时close,MediaScannerConnection没有调用disConnect等
                      ** 解决方案:及时关闭资源
                    1.2.4 Handler的使用造成的内存泄漏:由于在Handler的使用中,Handler会发送Message对象到MessageQueue中,然后Looper会轮询MessageQueue然后取出Message执行,但是如果一个Message长时间没有被取出执行,那么由于Message中有Handler的引用,而Handler一般来说是内部类对象,Message引用Handler,Handler引用Activity,这样就导致Activity无法被回收
                    ** 解决方案:使用静态内部类+弱引用方式解决,或者在Activity结束清空Handler的消息队列和一些回调,调用Handler.removeCallbackAndMessages(null)
                    1.2.5 广播监听注册之后没有解注册
                    ** 解决方案:比如使用EventBus后在onDestroy里面unRegister

    2.内存泄漏检测:Android Monitor + LeakCanary

使用LeakCanary进行内存溢出检测_第1张图片

使用LeakCanary进行内存溢出检测_第2张图片

如果有泄漏的Activity的话这里会列出具体的Activity名,然后左边就是该Activity引用的地方,可以自己分析,当然也可以借助LeakCanary来分析
    3.使用LeakCanary
    链接:https://github.com/square/leakcanary
    具体使用:1.添加Gradle配置
                     2.实现一个全局的RefWatcher获取方法,比如在Application里面构造一个

public class MainApplication extends Application {

    private RefWatcher mRefWatcher;

    @Override
    public void onCreate() {
        super.onCreate();
        mRefWatcher = initLeakCanary();
    }

    private RefWatcher initLeakCanary() {
        if (LeakCanary.isInAnalyzerProcess(this)) {
            return RefWatcher.DISABLED;
        }
        return LeakCanary.install(this);
    }

    public static RefWatcher getRefWatcher(Context context) {
        MainApplication application = (MainApplication) context.getApplicationContext();
        return application.mRefWatcher;
    }
}
                    3.在BaseActivity的onDestroy里面监听,调用MainApplication.getRefWatcher(this).watch(this);

                    4.运行安装app后操作自己的app,这个时候LeakCanary就会自动检测内存泄漏并会自动给出分析结果

使用LeakCanary进行内存溢出检测_第3张图片

你可能感兴趣的:(Android技术点,内存优化)