文章插图
图 8. 大对象链路
大对象不止分析了引用链路,还递归分析了内部 top 持有对象(InRefrenrece)的 RetainedSize 。
小对象

文章插图
图 9. 小对象链路
小对象我们对 top 的外部持有对象(OutRefrenrece)进行聚合得到占有小对象最多的链路 。
图片

文章插图
图 10. 图片链路
图片我们过滤了图片库等无效引用且对 Android 8.0 以下的大图在线下进行了还原 。

文章插图
回传分析为了最大限度的节省用户流量且规避隐私风险,我们通过自研 HPROF 裁剪工具 Tailor 在 dump 过程对 HPROF 进行了裁剪 。
裁剪过程

文章插图
图 11. Tailor 裁剪流程
去除了无用信息
- 跳过 header
- 分 tag 裁剪
- 裁剪无用信息:char[]; byte[]; timestamp; stack trace serial number; class serial number;
- 压缩数据信息
优化实践内存泄漏除了通过后台根据 GCROOT+ 引用链自动分配研发跟进解决我们常见的内存泄漏外,我们还对系统导致一些内存泄漏进行了分析和修复 。
系统异步 UI 泄漏根据上传聚合的引用链我们发现在 Android 6.0 以下有一个 HandlerThread 作为 GCROOT 持有大量 Activity 导致内存泄漏,根据引用发现这些泄漏的 Activity 都被一个 Runnable(这里是 Runnable 是一个系统事件 SendViewStateChangedAccessibilityEvent)持有,这些 Runnable 被添加到一个 RunQueuel 中,这个队列本身被 TheadLocal 持有 。

文章插图
图 12. HandlerThread 泄露链路
我们从 SendViewStateChangedAccessibilityEvent 入手对源码进行了分析发现它在 notifyViewAccessibilityStateChangedIfNeeded 中被抛出,系统的大量 view 都会在自身的一些 UI 方法(eg: setChecked)中触发该函数 。

文章插图
SendViewStateChangedAccessibilityEvent 的 runOrPost 方法会走到我们常用的 View 的 postDelay 方法中,这个方法在当 view 还未被 attched 到根 view 的时候会加入到一个 runQueue 中 。

文章插图
这个 runQueue 会在主线程下一次的 performTraversals() 中消费掉 。

文章插图
如果这个 runQueue 不在主线程那就没有消费的机会 。
根据上面的分析发现造成这种内存泄漏需要满足一些条件:
- view 调用了 postDelay 方法 (这里是 notifyViewAccessisbilityStateChangeIfNeeded 触发)
- view 处于 detached 状态
- 上述过程是在非主线程里面操作的,ThreadLocal 非 UIThread,持有的 runQueue 不会走 performTraversals 消费掉 。
抖音这边大量使用了异步 UI 框架来优化渲染性能,框架内部由一个 HandlerThread 驱动,完全符合上述条件 。针对该问题,我们通过反射获取非主线程的 ThreadLocal,在每次异步渲染完主动清理内部的 RunQueue 。

文章插图
图 13. 反射清理流程
另外,google 在 6.0 上也修复了 notifyViewAccessisbilityStateChangeIfNeeded 的判断不严谨问题 。

文章插图
内存泄漏兜底大量的内存泄漏,如果我们都靠推进研发解决,经常会出现生产大于消费的情况,针对这些未被消费的内存泄漏我们在客户端做了监控和止损,将 onDestory 的 Activity 添加到 WeakRerefrence 中,延迟 60s 监控是否回收,未回收则主动释放泄漏的 Activity 持有的 ViewTree 的背景图和 ImageView 图片 。
大对象主要对三种类型的大对象进行优化
- 全局缓存:针对全局缓存我们按需释放和降级了不需要的缓存,尽量使用弱引用代替强引用关系,比如针对频繁泄漏的 EventBus 我们将内部的订阅者关系改为弱引用解决了大量的 EventBus 泄漏 。
推荐阅读
- 使用GPU.js改善JavaScript性能
- 高性能负载均衡 DPVS 的 SNAT 功能介绍
- 聊聊CDN与高性能流媒体服务器的关键技术设计
- 充分榨干 CPU 的每一个 TICK:软件性能优化方法知多少
- 安卓|Android 14首曝:翻转蛋糕
- Android Jetpack 架构浅析
- 使用python爬取抖音app视频
- 搞懂Android应用启动过程,再也不怕面试官了
- Java内存泄漏、性能优化、宕机死锁的N种姿势
- 国外服务器速度太慢 四合一加速脚本/VPS性能代码详细教程
