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

1.概述

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

2.使用LeakCanary

首先配置build.gradle:

 dependencies {debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.2'releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.2'}
  • 1
  • 2
  • 3
  • 4

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

public class LeakApplication extends Application {@Override public void onCreate() {super.onCreate();if (LeakCanary.isInAnalyzerProcess(this)) {//1// This process is dedicated to LeakCanary for heap analysis.// You should not init your app in this process.return;}LeakCanary.install(this);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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

3.LeakCanary应用举例

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

public class LeakApplication extends Application {private RefWatcher refWatcher;@Overridepublic void onCreate() {super.onCreate();refWatcher= setupLeakCanary();}private RefWatcher setupLeakCanary() {if (LeakCanary.isInAnalyzerProcess(this)) {return RefWatcher.DISABLED;}return LeakCanary.install(this);}public static RefWatcher getRefWatcher(Context context) {LeakApplication leakApplication = (LeakApplication) context.getApplicationContext();return leakApplication.refWatcher;}
}

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

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);LeakThread leakThread = new LeakThread();leakThread.start();}class LeakThread extends Thread {@Overridepublic void run() {try {Thread.sleep(6 * 60 * 1000);} catch (InterruptedException e) {e.printStackTrace();}}}@Overrideprotected void onDestroy() {super.onDestroy();RefWatcher refWatcher = LeakApplication.getRefWatcher(this);//1refWatcher.watch(this);}
}
  • inActivity存在内存泄漏,原因就是非静态内部类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改为静态内部类。

public class MainActivity extends AppCompatActivity {...static class LeakThread extends Thread {@Overridepublic void run() {try {Thread.sleep(6 * 60 * 1000);} catch (InterruptedException e) {e.printStackTrace();}}}
...
}

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

Android系统性能优化(60)---LeakCanary使用详解相关推荐

  1. Android性能优化—MAT之OQL详解(三)

    OQL是Object Query Language的简写,即对象查询语言,OQL语法和关系型标准查询语言SQL的语法相似,只是增加了比如对象标识.复杂对象.操作.继承.多态性以及联系. SELECT ...

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

    相关文章 Android性能优化系列 Java虚拟机系列 1.概述 如果使用MAT来分析内存问题,会有一些难度,并且效率也不是很高,对于一个内存泄漏问题,可能要进行多次排查和对比. 为了能够简单迅速的 ...

  3. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)

       本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...

  4. Android init.rc文件解析过程详解(三)

    Android init.rc文件解析过程详解(三) 三.相关结构体 1.listnode listnode结构体用于建立双向链表,这种结构广泛用于kernel代码中, android源代码中定义了l ...

  5. Android  Doze and App Standby模式详解

    Android  Doze and App Standby模式详解 来源:腾云阁 https://www.qcloud.com/community Optimizing for Doze and Ap ...

  6. Android 系统属性读取和设置详解

    Android 系统属性读取和设置详解 一.在adb中进行属性读取和设置 1.Settings Provider设置和读取 获取 设置 2.SystemProperties属性读取和设置 二.Andr ...

  7. android 多闹钟实现代码,Android编程实现闹钟的方法详解

    Android编程实现闹钟的方法详解 发布时间:2020-09-30 10:18:02 来源:脚本之家 阅读:75 作者:Jacob-wj 本文实例讲述了Android编程实现闹钟的方法.分享给大家供 ...

  8. Android 4.1-Jelly Bean新特性详解

    Android 4.1Jelly Bean新特性详解 发布会已经结束,Android新一代的4.1版本,代号Jelly Bean(果冻豆)的新系统已经正式问世,除了新架构.全新通知栏和搜索功能之外,实 ...

  9. Android之TelephonyManager类的方法详解

    林计钦-JAVA java技术群:127834248 博客园   首页   社区   新随笔   联系   订阅   管理 随笔-105  评论-24  文章-0  trackbacks-0 Andr ...

最新文章

  1. JS计算起点坐标到终点坐标的驾车距离和驾车时间
  2. IT项目监理的三种模式比较
  3. CPU缓存一致性动态图
  4. 【theano-windows】学习笔记十——多层感知机手写数字分类
  5. VMwareWorkstation设置U盘启动(或U盘使用)
  6. .net core 调用c dll_C++ 调用C封装DLL库的两种方式
  7. 厉害了!厦门大学“嘉庚一号”火箭成功发射 问鼎九天
  8. 三菱Q系列PLC大型程序Q01U伺服12轴 实际使用中程序
  9. hotmail手机端_Hotmail邮箱客户端下载-Hotmail手机版下载 v2.48.0-pc6下载
  10. vb.net中datagridview取消首行选中_解锁Excel中那些隐藏很深但很实用的功能!真的太好用了!...
  11. centos 磁盘重新分区操作实践
  12. コナン純黒のナイトメア20180715
  13. 深度学习笔记(一)了解深度学习
  14. 2022年计网《宿舍网有线无线一体化项目》总结
  15. 关于Type-C扩展坞干扰路由器交换机的解决方案
  16. ROS学习(18)机器人SLAM功能包——cartographer的安装与测试
  17. pkg-config --cflags -- vips vips vips vipspkg-config: exec: “pkg-config“: executab的解决方案centos+ubuntu
  18. 【渝粤题库】广东开放大学 税务会计技术 形成性考核
  19. 基于PHP的火车票订票接口完成火车票订票流程
  20. android okhttp get 请求带参数

热门文章

  1. 数字图像处理(作业三)——孔洞填充+全局阈值+自适应阈值
  2. 崩坏3服务器维护2月8号,《崩坏3》8月29日版本更新,全服维护通知
  3. mysql的内连接与外连接
  4. java treemap value排序_【TreeMap】对Map按key和value分别排序
  5. 《深入理解 Spring Cloud 与微服务构建》第六章 服务注册和发现 Eureka
  6. python-flask-Flask-SQLAlchemy与Flask-Migrate联合进行数据化迁移
  7. 【转】ASCII码表
  8. xadmin在Django 1.11中的使用及中英文切换
  9. python第四课知识点总结
  10. (转载)关于ASCII和GB2312、GBK、GB18030、UNICODE