一篇文章教你搞定内存泄漏与排查流程——安卓性能优化( 二 )

(2) 可达性分析算法
 

一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
 
可达性分析算法是现在java的主流方法,通过一系列的GC ROOT为起始点,从一个GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点(即图中的ObjD、ObjE、ObjF) 。由此可知,即时引用成环也不会导致泄漏 。
java中可作为GC Root的对象有:
1、方法区中静态属性引用的对象
2、方法区中常量引用的对象
3、本地方法栈JNI中引用的对象(Native对象)
4、虚拟机栈(本地变量表)中正在运行使用的引用
但是,可达性分析算法中不可达的对象,也并非一定要被回收 。当GC第一次扫过这些对象的时候,他们处于“死缓”的阶段 。要真正执行死刑,至少需要经过两次标记过程 。 如果对象经过可达性分析之后发现没有与GC Roots相关联的引用链,那他会被第一次标记,并经历一次筛选,这个对象的finalize方法会被执行 。如果对象没有覆盖finalize或者已经被执行过了 。虚拟机也不会去执行finalize方法 。Finalize是对象逃狱的最后一次机会 。
3、四种引用说到底,内存泄漏是因为引用的处理不正当导致的 。所以,我们接下来需要老生常谈一下java中四种引用,即:强软弱虚(引用强度依次减弱) 。
(1)强引用(Strong reference): 一般我们使用的都是强引用,例如:Object o = new Object();只要强引用还在,垃圾收集器就不会回收被引用的对象 。
(2)软引用(Soft Reference): 用来定义一些还有用但并非必须的对象 。对于软引用关联着的对象,在系统将要内存溢出之前,会将这些对象列入回收范围进行第二次回收,如果回收后还是内存不足,才会抛出内存溢出 。(即在内存紧张时,会对其软引用回收)
(3)弱引用(Weak Reference): 用来描述非必须对象 。被弱引用关联的对象只能生存到下一次垃圾收集发生之前 。当垃圾收集器回收时,无论内存是否足够,都会回收掉被弱引用关联的对象 。(即GC扫过时,便将弱引用带走)
(4)虚引用(Phantom Reference): 也称为幽灵引用或者幻影引用,是最弱的引用关系 。一个对象的虚引用根本不影响其生存时间,也不能通过虚引用获得一个对象实例 。虚引用的唯一作用就是这个对象被GC时可以收到一条系统通知 。
软引用与弱引用的抉择
如果只是想避免OutOfMemory异常的发生,则可以使用软引用 。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用 。另外可以根据对象是否经常使用来判断选择软引用还是弱引用 。如果该对象可能会经常使用的,就尽量用软引用 。如果该对象不被使用的可能性更大些,就可以用弱引用 。
4、小结至此,我们知道内存泄漏是因为堆内存中的长生命周期的对象持有短生命周期对象的引用,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收 。
5、安卓内存泄漏排查工具所谓工欲善其事必先利其器,这一小节先简述下所需借用到的内存泄漏排查工具,如果已经熟悉的话可以跳过 。
(1) Android Profiler
这一工具是Android Studio自带,可以查看cpu、内存使用、网络使用情况,Android Studio3.0中用于替代Android Monitor
 
一篇文章教你搞定内存泄漏与排查流程——安卓性能优化

文章插图
 
 
① 强制执行垃圾收集事件的按钮 。
② 捕获堆转储的按钮 。
③ 记录内存分配的按钮 。
④ 放大时间线的按钮 。
⑤ 跳转到实时内存数据的按钮 。
⑥ 事件时间线显示活动状态、用户输入事件和屏幕旋转事件 。
⑦ 内存使用时间表,其中包括以下内容:
• 每个内存类别使用多少内存的堆栈图,如左边的y轴和顶部的颜色键所示 。
• 虚线表示已分配对象的数量,如右侧y轴所示 。
• 每个垃圾收集事件的图标 。
(2) MAT(Memory Analyzer Tool)
MAT用于锁定哪里泄漏 。因为从Android Profiler中,知道了泄漏,但比较难锁定具体哪个地方导致了泄漏,所以借助MAT来锁定,具体使用待会会借助一个例子配合Android Profiler来介绍,稍安勿躁 。
下载地址:www.eclipse.org/mat/downloa…


推荐阅读