线上正是由于上述一些弊端,抖音最早的线下工具和治理流程并没有起到什么太大作用,我们不得不重新审视一下,工具建设的重心从线下转成了线上 。线上工具的核心思路是:在发生 OOM 或者内存触顶等触发条件下,dump 内存的 HPROF 文件,对 HPROF 文件进行分析,分析出内存泄漏、大对象、小对象、图片问题并按照泄露链路自动归因,将大数据问题按照用户发生次数、泄露大小、总大小等纬度排序,推进业务研发按照优先级顺序来建立消费流程 。为此我们研发了一套基于 HPORF 分析的线下、线上闭环的自动化分析工具 Liko(寓意 ko 内存 Leak 问题) 。
Liko 介绍Liko 整体架构
文章插图
图 3. Liko 架构图
整体架构由客户端、Server 端和核心分析引擎三部分构成 。
- 客户端
线上:主要在 OOM 和内存触顶时通过用户无感知 dump 来获取 HPROF 文件,当 App 退出到后台且内存充足的情况进行分析,为了尽量减少对 App 运行时影响,主要通过裁剪 HPROF 回传进行分析,减轻服务器压力,对部分比例用户采用端上分析作为 Backup 。
线下:dump 策略配置较为激进,在 OOM、内存触顶、内存激增、监测 Activity、Fragment 泄漏数量达到一定阈值多种场景下触发 dump,并实时在端上分析上传至后台并在本地自动生成 html 报表,帮助研发提前发现可能存在的内存问题 。
- Server 端
- 分析引擎
Liko 流程图
文章插图
图 4. Liko 流程图
整体流程分为:
- Hprof 收集
- 分析时机
- 分析策略
为了解决 dump 挂起进程问题,我们采用了子进程 dump+fileObsever 的方式完成 dump 采集和监听 。
在 fork 子进程之前先 Suspend 获取主进程中的线程拷贝,通过 fork 系统调用创建子进程让子进程拥有父进程的拷贝,然后 fork 出的子进程中调用 Hprof 的 DumpHeap 函数即可完成把耗时的 dump 操作在放在子进程 。由于 suspend 和 resume 是系统函数,我们这里通过自研的 native hook 工具对 libart.so hook 获取系统调用 。由于写入是在子进程完成的,我们通过 Android 提供的 fileObsever 文件写入进行监控获取 dump 完成时机 。
文章插图
图 5.子进程 dump 流程图
Hprof 分析时机为了达到分析过程对于用户无感,我们在线上、线下配置了不同的分析时机策略,线下在 dump 分析完成后根据内存状态主动触发分析,线上当用户下次冷启退出应用后台且内存充足的情况下触发分析 。
分析策略分析策略我们提供了两种,一种在 Android 客户端分析,一种回传至 Server 端分析,均通过 MAT 分析引擎进行分析 。
端上分析分析引擎端上分析引擎的性能很重要,这里我们主要对比了 LeakCanary 的分析引擎 Shark 和 Haha 库的 MAT 。
文章插图
图 6. Shark VS MAT
我们在相同客户端环境对 160M 的 HPROF 多次分析对比发现 MAT 分析速度明显优于 Shark,另外针对 MAT 分析后仍持有统治者树占用内存我们也做了主动释放,对比性能收益后采用基于 MAT 库的分析引擎进行分析,对内存泄漏引用链路自动归并、大对象小对象引用链自动分析、大图线下自动还原线上过滤无用链路,分析结果如下:
内存泄漏
文章插图
图 7. 内存泄漏链路
对泄漏的 Activity 的引用链进行了聚合分析,方便一次性解决该 Activity 的泄漏链释放内存 。
大对象
推荐阅读
- 使用GPU.js改善JavaScript性能
- 高性能负载均衡 DPVS 的 SNAT 功能介绍
- 聊聊CDN与高性能流媒体服务器的关键技术设计
- 充分榨干 CPU 的每一个 TICK:软件性能优化方法知多少
- 安卓|Android 14首曝:翻转蛋糕
- Android Jetpack 架构浅析
- 使用python爬取抖音app视频
- 搞懂Android应用启动过程,再也不怕面试官了
- Java内存泄漏、性能优化、宕机死锁的N种姿势
- 国外服务器速度太慢 四合一加速脚本/VPS性能代码详细教程