线下
线下工具是最先考虑的,在研发和测试的时候能够提前发现内存泄漏问题。业界的主流工具也是这个思路,比如 Android Studio Memory Profiler、LeakCanary、Memory Analyzer (MAT)。
我们基于 LeakCanary 核心库在线下设计了一套自动分析上报内存泄露的工具,主要流程如下:
图 2.线下自动分析流程
抖音在运行了一段线下的内存泄漏工具之后,发现了线下工具的各种弊端:
-
检测出来的内存泄漏过多,并且也没有比较好的优先级排序,研发消费不过来,历史问题就一直堆积。另外也很难和业务研发沟通问题解决的收益,大家针对解决线下的内存泄漏问题的 ROI(投入产出比)比较难对齐。
-
线下场景能跑到的场景有限,很难把所有用户场景穷尽。抖音用户基数很大,我们经常遇到一些线上的 OOM 激增问题,因为缺少线上数据而无从查起。
-
Android 端的 HPORF 的获取依赖原生的
Debug.dumpHporf
,dump 过程会挂起主线程导致明显卡顿,线下使用体验较差,经常会有研发反馈影响测试。 -
LeakCanary 基于 Shark 分析引擎分析,分析速度较慢,通常在 5 分钟以上才能分析完成,分析过程会影响进程内存占用。
-
分析结果较为单一,仅仅只能分析出 Fragment、Activity 内存泄露,像大对象、过多小对象问题导致的内存 OOM 无法分析。
线上
正是由于上述一些弊端,抖音最早的线下工具和治理流程并没有起到什么太大作用,我们不得不重新审视一下,工具建设的重心从线下转成了线上。线上工具的核心思路是:在发生 OOM 或者内存触顶等触发条件下,dump 内存的 HPROF 文件,对 HPROF 文件进行分析,分析出内存泄漏、大对象、小对象、图片问题并按照泄露链路自动归因,将大数据问题按照用户发生次数、泄露大小、总大小等纬度排序,推进业务研发按照优先级顺序来建立消费流程。为此我们研发了一套基于 HPORF 分析的线下、线上闭环的自动化分析工具 Liko(寓意 ko 内存 Leak 问题)。
Liko 介绍
Liko 整体架构
图 3. Liko 架构图
整体架构由客户端、Server 端和核心分析引擎三部分构成。
- 客户端
在客户端完成 HPROF 数据采集和分析(针对端上分析模式),这里线上和线下策略不同。
线上:主要在 OOM 和内存触顶时通过用户无感知 dump 来获取 HPROF 文件,当 App 退出到后台且内存充足的情况进行分析,为了尽量减少对 App 运行时影响,主要通过裁剪 HPROF 回传进行分析,为减轻服务器压力,对部分比例用户采用端上分析作为 Backup。
线下:dump 策略配置较为激进,在 OOM、内存触顶、内存激增、监测 Activity、Fragment 泄漏数量达到一定阈值多种场景下触发 dump,并实时在端上分析上传至后台并在本地自动生成 html 报表,帮助研发提前发现可能存在的内存问题。
- Server 端
Server 端根据线上回传的大数据完成链路聚合、还原、分配,并根据用户发生次数、泄露大小、总大小等纬度促进研发测消费,对于回传分析模式则会另外进行 HPORF 分析。
- 分析引擎
基于 MAT 分析引擎完成内存泄露、大对象、小对象、图片等自动归因,同时支持在线下自动生成 Html 报表。
Liko 流程图
图 4. Liko 流程图
整体流程分为:
-
Hprof 收集
-
分析时机
-
分析策略
Hprof 收集
收集过程我们设置了多种策略可以自由组合,主要有 OOM、内存触顶、内存激增、监测 Activity、Fragment 泄漏数量达到一定阈值时触发,线下线上策略配置不同。
为了解决 dump 挂起进程问题,我们采用了子进程 dump+fileObsever 的方式完成 dump 采集和监听。
在 fork 子进程之前先 Suspend
获取主进程中的线程拷贝,通过 fork 系统调用创建子进程让子进程拥有父进程的拷贝,然后 fork 出的子进程中调用 Hprof 的 DumpHeap