概要

项目也使用LeakCanary一段时间了,也确实检测出了内存泄露,只是碍于项目进度,一直没有去进行分析。现在有时间了,就开始着手进行分析。LeakCanary泄露如下:

欢迎页泄露了26M,可怕吧。

过程

  1. 首先需要找出泄露的根源,LeakCanary也提供了这方面的帮助,点击泄露的项进去如下所示:

    可以发现是线程导致的内存泄露,但是提供的信息还太小,所以接下来需要使用一个更高级的工具-MAT(Memory Analyzer), MAT需要使用到hprof文件,当然贴心的LeakCanary也提供了这方面的支持,点击图中的Share heap dump,既可以生成hprof文件,不过安卓生成的hprof文件不能直接被MAT识别,需要进入到android sdk中的platform-tools通过命令行进行转换: hprof-conv before.hprof format.hprof,除了这种方式之外,也可以通过android studio自带的Android Profiler工具生成hprof文件,进入Android Profiler,进入Memory模式,接着点击图中红色框框中的按钮进行dump,之后会dump一段时间然后进行分析,如下

    最后,只要点击红色框的保存按钮,即可以保存一份hprof文件,当然这个也需要经过上面的命令转换。
  2. 接下来使用MAT工具,打开转换后的文件,如下:

    然后点击框中的按钮,进入domiator_tree分析,然后在编辑框搜索WelcomeActivity,搜索结果如下:
    ,接着右键Path To GCRoots,并且除去其他的弱引用等。

    得到的结果如下图,可以发现线程的来源于第三方服务——极光推送

    接着进入极光推送的jar包进行查看cn.jiguang.d.d.q这个类的变量a,如下
    ,到这里真相终于水落石出,q这个类是Runnable的实现并且持有了WelcomeActivity的context引用,由于线程的异步执行导致了WelcomeActivity即使销毁,context仍然被持有从而泄露。LeakCancary提到的泄露线程的名字是pool-11-thread-1, 我们可以查出这个引用这个线程的线程池就可以得到相关的信息了,如下
    ,线程池的名字前缀是pool-11-thread-, 而threadNumber = 2是先赋值再增,所以赋值给泄露线程的值是1,所以可知泄露线程的名字是pool-11-thread-1。
  3. 总结如下,由于在WelcomeActivity中调用了极光的服务,而极光的服务持有了他的context并且赋值给线程,因此导致了context无法被回收而导致内存泄露。

总结

   首先需要了解LeakCanary的原理,可以参考这篇文章LeakCanary原理浅析,原理大致如下:LeakCanary在活动A销毁的时候,进行观察,给活动A加上了弱引用WeakReference还有ReferenceQueue。ReferenceQueue有这样一个特性,如果WeakReference持有的类被回收了,就会进入ReferenceQueue队列里面,我们只需要让队列出队,如果出队的类存在,说明这个类没有其他的GcRoots所引用,即可认为该类已经回收不存在泄露。如果类泄露了,那么LeakCanary会再进行dump heap的分析,得到泄露的路径。
   最后,我想到了一个问题,如果持有context的线程已经结束了,那么内存还能释放吗?这里就需要使用到GcRoots的相关知识了,那么GcRoots都有哪些呢,如下:

常说的GC(Garbage Collector) roots,特指的是垃圾收集器(Garbage Collector)的对象,GC会收集那些不是GC roots且没有被GC roots引用的对象。
一个对象可以属于多个root,GC root有几下种:
Class - 由系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。我们需要注意的一点就是,通过用户自定义的类加载器加载的类,除非相应的java.lang.Class实例以其它的某种(或多种)方式成为roots,否则它们并不是roots,.
Thread - 活着的线程
Stack Local - Java方法的local变量或参数
JNI Local - JNI方法的local变量或参数
JNI Global - 全局JNI引用
Monitor Used - 用于同步的监控对象
Held by JVM - 用于JVM特殊目的由GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。然而,JVM并没有为这些对象提供其它的信息,因此需要去确定哪些是属于”JVM持有”的了。

所以对于线程来说,重点是活着的线程,如果线程已经执行结束了,已经不是GcRoots并且没有其他引用,那么线程也会被回收,从而被引用的context也能得到释放,内存也能得到回收,这个我也有进行,内存确实能够得到回收。但是对于LeakCanary而言,它关注的是活动销毁时的状态,它并没有跟踪活动之后的状态,所以LeakCanary的最大作用就是给我们提个醒,让我们早点发现和规避内存的泄露。

参考

Mat内存优化
LeakCanary原理浅析
GcRoots

一次内存泄露的分析及总结相关推荐

  1. Android使用Handler造成内存泄露的分析及解决方法

    Android使用Handler造成内存泄露的分析及解决方法 参考文章: (1)Android使用Handler造成内存泄露的分析及解决方法 (2)https://www.cnblogs.com/xu ...

  2. 关于Android 的内存泄露及分析

    博客园 首页 新随笔 联系 管理 订阅 随笔- 137  文章- 6  评论- 145  关于Android 的内存泄露及分析 一. Android的内存机制 Android的程序由Java语言编写, ...

  3. ThreadLocal是否会引发内存泄露的分析 good

    这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...

  4. java thread 内存泄露_Java ThreadLocal 内存泄露问题分析及解决方法。

    前言 在分析ThreadLocal导致的内存泄露前,需要普及了解一下内存泄露.强引用与弱引用以及GC回收机制,这样才能更好的分析为什么ThreadLocal会导致内存泄露呢?更重要的是知道该如何避免这 ...

  5. Spark内存泄露问题分析追查

    本文分析思路非常清晰,这里转载作为学习分析spark内存泄露问题的案例.(原文见文章末尾参考) [Abstract] I recently encountered an OOM error in a ...

  6. JVM垃圾回收与一次线上内存泄露问题分析和解决过程

    前言 内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果. Java是由C++发展来的,抛弃 ...

  7. Android中使用Handler(消息机制)造成内存泄露的分析和解决

    问题描述: Handler 内部类持有 外部类Activity的引用,如果Activity退出而Handler还有延迟处理的消息没有处理完,会导致Activity不能回收,反复如此会导致内存泄露. 解 ...

  8. Android Handler的内存泄露场景分析

    在前面一篇博客<Android全面解析Handler>一文中,我们认识了Handler的异步通信机制,同时也提到过Handler如果使用不慎将会导致内存泄露.今天主要来讲述一下Handle ...

  9. 内存泄露Lowmemorykiller分析

    01 前言 最近疫苗事情非常火热,这件事情让我对刘强东有点刮目相看,我们需要更多的人关注曝光此类问题 02 正文 Android Kernel 会定时执行一次检查,杀死一些进程,释放掉内存.Low m ...

  10. .net内存泄露问题分析

    一.问题背景 最近在对客户采集服务优化的时候,无意间点开客户服务器上另外一个我们的小的采集服务,发现一堆错误日志,一直在报"OutOf memory"错误,查看服务占用内存1.7G ...

最新文章

  1. 《统一沟通-微软-实战》-5-部署-SharePoint Server 2010
  2. java foreach 原理_一不小心就让Java开发者踩坑的failfast是个什么鬼?
  3. 理解Shadow DOM
  4. 简练软考知识点整理-控制成本过程
  5. C语言编程笔记:关于 for循环 的那些不为人知的秘密
  6. asp.net listview 字段太多 滚动条_高考英语阅读理解生僻单词太多怎么办?十大招数帮到你...
  7. 如何爬取ajax实时加载多个ts文件的视频
  8. java 货币格式 转换_java 货币 转换
  9. 【数据结构】班级管理系统
  10. Mapbox使用之glyphs(字体符号)
  11. ICCV 2019|70 篇论文抢先读,含目标检测/自动驾驶/GCN/等(提供PDF下载)
  12. xampp运行不成功或者安装过程中提示找不到文件“-n”,没有安装vcredist_x86的解决方法
  13. 分布式系统原理(5)Quorum 机制
  14. Win10跳过开机登录界面
  15. 矩阵的模的平方matlab,matlab求矩阵、向量的模
  16. C语言圣诞树(精修版)附图(有初学者版还有进阶版)
  17. 目标检测框架网络模型分析(二 双塔奇兵)
  18. 《趣谈网络协议》学习笔记 DAY04
  19. 深度学习制作自己的数据集—为数据集打上标签保存为txt文件,并进行划分和加载数据集
  20. 兰卡斯特的计算机科学与技术,兰卡斯特大学计算机专业好吗

热门文章

  1. python刷b站视频浏览量_python刷B站播放量
  2. hex文件、bin文件、axf文件的区别?
  3. Matlab中max函数详解
  4. RabbitMQ学习总结(一)
  5. 03、单线通讯—SIF通讯协议(一线通)案例二
  6. 头的各个部位示意图_人体头部结构图:人体图片头部组织图文解读
  7. 单独使用mybatis整合mysql案例
  8. 英语句子组织的5个步骤
  9. H5拼团抽奖拆盲盒源码/价值几万的H5拼团抽奖拆盲盒模式源码
  10. 史上最全的程序员常用英语词汇 建议收藏!