Android内存优化(六)LeakCanary使用详解

1.概述

如果使用MAT来分析内存问题,会有一些难度,并且效率也不是很高,对于一个内存泄漏问题,可能要进行多次排查和对比。 为了能够简单迅速的发现内存泄漏,Square公司基于MAT开源了LeakCanary。

2.使用LeakCanary

首先配置build.gradle:

接下来在Application加入如下代码。

注释1处的代码用来进行过滤操作,如果当前的进程是用来给LeakCanary 进行堆分析的则return,否则会执行LeakCanary的install方法。这样我们就可以使用LeakCanary了,如果检测到某个Activity 有内存泄露,LeakCanary 就会给出提示。

3.LeakCanary应用举例

第二节的例子代码只能够检测Activity的内存泄漏,当然还存在其他类的内存泄漏,这时我们就需要使用RefWatcher来进行监控。改写Application,如下所示。

install方法会返回RefWatcher用来监控对象,LeakApplication中还要提供getRefWatcher静态方法来返回全局RefWatcher。最后为了举例,我们在一段存在内存泄漏的代码中引入LeakCanary监控,如下所示。

MainActivity存在内存泄漏,原因就是非静态内部类LeakThread持有外部类MainActivity的引用,LeakThread中做了耗时操作,导致MainActivity无法被释放。关于内存泄漏可以查看Android内存优化(三)避免可控的内存泄漏这篇文章。在注释1处得到RefWatcher,并调用它的watch方法,watch方法的参数就是要监控的对象。当然,在这个例子中onDestroy方法是多余的,因为LeakCanary在调用install方法时会启动一个ActivityRefWatcher类,它用于自动监控Activity执行onDestroy方法之后是否发生内存泄露。这里只是为了方便举例,如果想要监控Fragment,在Fragment中添加如上的onDestroy方法是有用的。

运行程序,这时会在界面生成一个名为Leaks的应用图标。接下来不断的切换横竖屏,这时会闪出一个提示框,提示内容为:“Dumping memory app will freeze.Brrrr.”。再稍等片刻,内存泄漏信息就会通过Notification展示出来,比如三星S8的通知栏如下所示。

Notification中提示了MainActivity发生了内存泄漏, 泄漏的内存为787B。点击Notification就可以进入内存泄漏详细页,除此之外也可以通过Leaks应用的列表界面进入,列表界面如下图所示。

内存泄漏详细页如下图所示。

点击加号就可以查看具体类所在的包名称。整个详情就是一个引用链:MainActiviy的内部类LeakThread引用了LeakThread的this$0this$0的含义就是内部类自动保留的一个指向所在外部类的引用,而这个外部类就是详情最后一行所给出的MainActiviy的实例,这将会导致MainActivity无法被GC,从而产生内存泄漏。

除此之外,我们还可以将 heap dump(hprof文件)和info信息分享出去,如下图所示。

需要注意的是分享出去的hprof文件并不是标准的hprof文件,还需要将它转换为标准的hprof文件,这样才会被MAT识别从而进行分析,关于MAT可以查看Android内存优化(五)详解内存分析工具MAT这篇文章。

解决方法就是将LeakThread改为静态内部类。

再次运行程序LeakThread就不会给出内存泄漏的提示了。

原文发布于微信公众号 - 刘望舒(liuwangshuAndroid)

原文发表时间:2017-09-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏C/C++基础

C风格简易本地log系统

该C风格简易log日志系统,适合与Linux平台系统,主要用于格式化输出日志到本地指定的文件中,可指定log文件数目、最大大小、行数、按时间切换等功能,可满足基...

17340
来自专栏刘望舒

Android网络编程(九)Retrofit2前篇[基本使用]

前言 Retrofit是Square公司开发的一款针对Android网络请求的框架,Retrofit2底层基于OkHttp实现的,而OkHttp现在已经得到Go...

20860
来自专栏Linux驱动

QT-第一个程序 Hello QT , 以及QT creator介绍

第一个程序 - Hello QT 首先写main.cpp: #include <QApplication> #include <QMainWindow> #in...

40570
来自专栏Coding迪斯尼

java开发系统内核:使用LDT保护进程数据和代码

11330
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列24-spring(3)-配置文件相关问题

Java面试系列24-spring(3)-配置文件相关问题 12.解释一下Dependency Injection(DI)和IOC(inversion of ...

29240
来自专栏Java帮帮-微信公众号-技术文章全总结

RabbitMQ详解解答【面试+工作】

如果安装rabbitMQ首先安装基于erlang语言支持的OTP软件,然后在下载rabbitMQ软件进行安装(安装过程都是下一步,在此不在说了)

37110
来自专栏Java3y

Hibernate面试题大全

Hibernate常见面试题 Hibernate工作原理及为什么要用? Hibernate工作原理及为什么要用? 读取并解析配置文件 读取并解析映射信息,创建...

44150
来自专栏求索之路

Android数据层架构的实现 上篇

最近我们app的服务器吃不消了,所以我在为服务器增加缓存层之后,又想到在app端进行二级缓存以减少app对服务器的访问。我想很多app应该在项目的初期架构的时...

32580
来自专栏求索之路

全面剖析SharedPreferences

1.原理和概述 1.储存于硬盘上的xml键值对。 2.轻量级数据储存,数据多了容易引起性能问题 3.xml文件所在目录位于/data/data//shared_...

31550
来自专栏大葡萄元元

Android SDK上手指南:知识测试

在从零开始学习Android SDK系列教程当中,我们已经了解了为Android平台创建应用程序过程中需要涉及的各种基本概念及知识要点。一路走来,我们探讨了关于...

11620

扫码关注云+社区

领取腾讯云代金券