android 内存泄露分析及调试(LeakCanary使用)

LeakCanary是一个傻瓜化并且可视化的内存泄露分析工具

为什么需要LeakCanary?
因为它简单,易于发现问题,人人可参与。

简单:只需设置一段代码即可,打开应用运行一下就能够发现内存泄露。而MAT分析需要Heap Dump,获取文件,手动分析等多个步骤。
易于发现问题:在手机端即可查看问题即引用关系,而MAT则需要你分析,找到Path To GC Roots等关系。
人人可参与:开发人员,测试测试,产品经理基本上只要会用App就有可能发现问题。而传统的MAT方式,只有部分开发者才有精力和能力实施。

什么是内存泄露?

一些对象有着有限的生命周期。当这些对象所要做的事情完成了,我们希望他们会被回收掉。但是如果有一系列对这个对象的引用,那么在我们期待这个对象生命周期结束的时候被收回的时候,它是不会被回收的。它还会占用内存,这就造成了内存泄露。持续累加,内存很快被耗尽。( 简而言之,某个对象在该释放的时候由于被其他对象持有没有被释放,因而造成了内存泄露。

比如,当 Activity.onDestroy 被调用之后,activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。但是,如果有一个后台线程持有这个 activity 的引用,那么 activity 对应的内存就不能被回收。这最终将会导致内存耗尽,然后因为 OOM 而 crash。

常见内存泄露:

http://blog.csdn.net/gemmem/article/details/13017999

Android中使用Thread造成内存泄露的分析和解决

官网解释:https://medium.com/square-corner-blog/leakcanary-detect-all-memory-leaks-875ff8360745

如何集成?
尽量在app下的build.gradle中加入以下依赖

testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1'
接下来,在你的应用里写一个自定义 Application ,并在其中“安装” RefWatcher:
public class MyApplication extends Application {
    private static RefWatcher sRefWatcher;


    @Override
    public void onCreate() {
        super.onCreate();
        sRefWatcher = LeakCanary.install(this);
    }

    public static RefWatcher getRefWatcher() {
        return sRefWatcher;
    }
}

监控某个可能存在内存泄露的对象
MyApplication.getRefWatcher().watch(sLeaky);

哪些需要进行监控?

默认情况下,是对Activity进行了检测。另一个需要监控的重要对象就是Fragment实例。因为它和Activity实例一样可能持有大量的视图以及视图需要的资源(比如Bitmap)即在Fragment onDestroy方法中加入如下实现

public class MainFragment extends Fragment {
    @Override
    public void onDestroy() {
        super.onDestroy();
        MyApplication.getRefWatcher().watch(this);
    }
}

何时进行监控?
首先,我们需要明确什么是内存泄露,简而言之,某个对象在该释放的时候由于被其他对象持有没有被释放,因而造成了内存泄露。
因此,我们监控也需要设置在对象(很快)被释放的时候,如Activity和Fragment的onDestroy方法。
一个错误示例,比如监控一个Activity,放在onCreate就会大错特错了,那么你每次都会收到Activity的泄露通知。

如何解决?
常用的解决方法思路如下:
尽量使用Application的Context而不是Activity的;
使用弱引用或者软引用;
手动设置null,解除引用关系;
将内部类设置为static,不隐式持有外部的实例;
注册与反注册成对出现,在对象合适的生命周期进行反注册操作;
如果没有修改的权限,比如系统或者第三方SDK,可以使用反射进行解决持有关系;

如何使用LeakCanary?

http://www.jianshu.com/p/a8900eb3de12

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0511/2861.html

使用注意:

需要设置相应的文件存储和查看权限;我所遇到的内存泄露问题,可参考:http://blog.csdn.net/jdsjlzx/article/details/51388847

ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        for (int i = 0; i < 10; i++) {
            final int pos = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    String threadName = Thread.currentThread().getName();
                    Log.e("TAG", "线程" + threadName + "任务" + pos);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }

相关参考文章:

http://droidyue.com/blog/2016/03/28/android-leakcanary/

http://blog.csdn.net/clevergump/article/details/50995612

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值