罗鑫 手QiOS性能监控和优化实践

前端狗

2019/07/09 发布于 编程 分类

GMTC2019 

文字内容
1. 手Q iOS客户端性能监控和优化实践 罗鑫(rosen)
2. 自我介绍
3. 自我介绍
4. 自我介绍 罗鑫(rosen),来自腾讯 QQ研发中心。2015年加入腾讯手Q团队,主要工 作是负责手Q iOS性能监控体系的建设,在卡顿、内存、发热耗电和Crash等移 动终端的性能问题优化有丰富的实践经验,目前是手Q iOS客户端性能负责人。
5. 目录 1. App性能-移动终端的兵家必争之地 2. 卡顿优化-为App流畅度保驾护航 3. 内存优化-合理利用每一块内存 4. 节能省电-移动终端的独有挑战 5. 机器学习和大数据在性能监控的应用
6. 目录 1. App性能-移动终端的兵家必争之地 2. 卡顿优化-为App流畅度保驾护航 3. 内存优化-合理利用每一块内存 4. 节能省电-移动终端的独有挑战 5. 机器学习和大数据在性能监控的应用
7. 手Q在发展中遇到的性能挑战 性能问题主要有三类: 动不动就闪退 1.随机卡顿 看图片卡住闪退 手机发热,烫死了 场景不固定,一般没有规律复现定位困难 2.爆内存闪退问题 内存使用不当引发的爆内存闪退,无法被传统手段捕获 怎么这么耗电? 老是卡顿,郁闷 3.发热耗电 不当逻辑引发的耗电太多或者手机发热严重 思考: 用户反馈 要有完善的线上工具监控和定位相关性能问题
8. 手Q APM线上性能监控体系 客户端采集 卡顿 卡顿监控 卡死监控 内存 APM系统 问题跟进 用户 版本 发布 灰度用户 正式用户 触顶监控 爆内存监控 1. 堆栈还原 2. 问题聚类 发热耗电 CPU XG流量 GPS IO量 3. 自动提单 1. 专项优化 2. Bug跟进 版本 发布
9. 目录 1. App性能-移动终端的兵家必争之地 2. 卡顿优化-为App流畅度保驾护航 3. 内存优化-合理利用每一块内存 4. 节能省电-移动终端的独有挑战 5. 机器学习和大数据在性能监控的应用
10. 从手Q早期典型卡顿案例说起 14年开始就有用户反馈手Q使用中经常卡顿 卡顿堆栈 问题特点: 难复现:场景不固定,问题发生无规律 难定位:大部分不必现,日志无法准确打点 问题原因: 当NSUserDefault组件在系统低内存时会把内存中的数据进行置 换,在执行的过程中会加锁,此时在主线程访问NSUserDefault 会导致长时间卡顿 Thread 0:", "1 CoreFoundation -[CFPrefsSearchListSource generationCountFromListOfSources:count:] (in CoreFoundation) + 76", "2 CoreFoundation -[CFPrefsSearchListSource alreadylocked_copyDictionary] (in CoreFoundation) + 164", "3 CoreFoundation -[CFPrefsSearchListSource alreadylocked_copyValueForKey:] (in CoreFoundation) + 52", "4 CoreFoundation ___CFPreferencesCopyAppValueWithContainer_bloc k_invoke (in CoreFoundation) + 72"
11. 手Q卡顿监控方案演进史 第一版 OC入口方法Hook Hook objc_msgsend、NSNotificaiton和 NSTimer和perforselector OC函数入口, 打印方法耗时 第二版 基于RunLoop observer 抓栈 监控方案 主线程监听NSRunloop observer,子线程 利用NSTimer定时抓取堆栈 第三版 基于CADisplayLink 回调的抓栈 监控方案 主线程监听CADisplayLink屏幕刷新回调, 子线程利用CADisplayLink回调抓取堆栈
12. 基于CADisplayLink的卡顿监控方案 方案概述: Main Thread 利用CADisplayLink提供的屏幕刷新回调,在主线 程两次刷新之间通过高优先级子线程持续抓取主线 程堆栈 CADisplaylink 16.7ms 16.7ms 1000ms …… Suspend & Capture High Priotity Thread 1 Stack 1 Stack 方案优势: 1 Stack 1.屏幕刷新回调,保证所有卡顿都不会遗漏 60 Stacks 2.CADisplayLink硬件事件回调,相比NSTimer更 加精准无延迟 main 24帧 400ms A B C D E 100ms 300ms 600ms 36帧 600ms 3.子线程直接抓取堆栈,抓取效率高
13. 堆栈抓取原理 Func0 --> Func1 --> Func2 SP Before Calling Func2 …… After Calling Func2 …… LR(Func0) LR(Func0) FP FP Local Storage Local Storage FP SP LR(Func1) FP Local Storage Suspend Thread 方案优点: 1.单次采集耗时0.2ms,性能开销小 2.整体CPU消耗<2%左右 技术要点: • 判断Frame Pointer合理性,避免栈帧逆向增长 • 提前分配内存,避免死锁 • 卡顿一般只抓主线程堆栈,超过5秒抓一次全部线 程堆栈
14. iOS常见卡顿问题总结 1.NSUserDefaults:低内存的情况下,系统拷贝内存数据到磁盘 2.I/O:文件读写、数据库操作 3.系统接口:获取mac地址、切换音频设备、读取桌面icon未读数 4.死锁以及锁的滥用 5.排版绘制: sizeWithFont、 [EAGLContext setCurrentContext:] 6.GCD并发队列短时间创建大量任务 7.UIWebview初始化、销毁(使用性能更优的WKWebView)
15. 如何在快速的版本迭代中保证App性能不恶化? 三大机制为App性能保驾护航: 灰度/线上 1.分支新增卡顿:基于分支代码提交记录和卡 顿堆栈精准匹配 卡顿聚类树 新旧版本 卡顿对比 研发流程内 2.卡顿聚类树版本卡顿对比:利用大盘用户的 大数据,与历史版本进行对比分析发现新增 问题,需要说明的是占比或者卡顿耗时变化 较大的也是新增卡顿 3.页面流畅度专项优化:建立页面性能负责人 机制,对于新版本流畅度下降的页面专项优 化 分支 新增卡顿合流 自动检测 APM 页面流畅度 专项优化
16. 目录 1. App性能-移动终端的兵家必争之地 2. 卡顿优化-为App流畅度保驾护航 3. 内存优化-合理利用每一块内存 4. 节能省电-移动终端的独有挑战 5. 机器学习和大数据在性能监控的应用
17. 从爆内存典型案例说起 有部分用户反馈升级ios10后手Q启动10秒内必现闪退 问题特点: 难发现:爆内存属于SIGKILL闪退,不可捕获 难复现:特定用户+特定场景,内网无法复现 难定位:系统jetsam日志无定位堆栈,无迹可寻 问题原因: 手Q通讯录的循环遍历逻辑中没有加autoreleasepool, 当用户通讯 录较多时会积累大量autorelease对象从而引发内存暴涨最终被系统 kill
18. . SIGKILL O 1 发现爆内存问题:SIGKILL闪退识别 App启动 E YES cY P App或系统版本号是否与上次 e 运行时不同 c App或系统升级 YES APP Crashed F NS bA ha kp 基于Facebook方案,结合实践经验改进点: No No 1. 优化IO失败导致的误报 2 I 上次运行时Crash组件是否检测到 e P Crash 2 . 2. 优化Crash捕获组件,避免Crash组件内部逻辑引发的二次 No 用户主动退出或者后台 5 dC 被杀 o YES 上次运行时是否退后台了 e P C . . I C Crash和内部内存分配导致的卡死 No 3. 结合卡顿组件,区分卡死情况,上报卡死堆栈定位问题 3 C C 5 P 主线程是否卡顿 超过5秒 YES 卡死:上报卡死堆栈 No 爆内存:上报内存堆栈
19. 让爆内存问题“有的放矢”:爆内存堆栈监控方案 独立 malloc zone 方案概述: malloc/free Hook所有内存分配方法,记录并抓取所有内存分配的堆 Malloc堆内存 hook Hook 堆栈回溯 栈和内存大小 内存对象缓存池 堆栈聚类 VM虚拟内存 实现中遇到的问题: 大块内存 直接上报 1. 如何Hook内存分配方法? • 替换全局函数指针malloc_logger mmap SIGKILL 爆内存 卡死 下次启动后检 测到异常退出 普通Crash 爆内存 磁盘数据 对象内存堆栈 上报 内存监控平台 云分析 2. 如何解决工具内部内存分配递归死循环问题? • 使用独立malloc zone,隔离内部内存分配 3. 如何保证堆栈数据及时落地? • 使用mmap保证数据不丢失 4. 如何保证工具开启不影响用户体验? • 深度优化工具内存和性能
20. 如何解决内存监控工具自身性能问题? 工具性能优化关键点: Hook内存分配方法 面临的挑战: 调用频率:10w次/秒 存活对象:>25W个 1.使用自旋锁代替互斥锁,提升对象缓存池的访问效率 2.对相同堆栈进行合并压缩,对于内存占用不高的堆栈,只存储 压缩后的摘要信息;只有当堆栈内存超过一定阀值时,才存储 堆栈的原始信息 3.优化摘要算法,一开始使用的是md5算法,后来优化为性能和 内存都更优的crc64算法 4.抽样策略:对于小块内存抽样采集,大块内存全量采集
21. iOS 常见内存问题总结 1. UIWebView:UIWebView的内存消耗很大,是内存问题的“重灾区”,优化方案是用 WKWebView替换 2. 大界面渲染:指View的size过大或者渲染结构过于复杂的界面渲染,优化方案是降低界面复 杂度 3. Autorelease对象:由于autorelease对象积累过多导致峰值内存增大爆内存,常见于大循 环和GCD串行队列中 4. 大图片解码:这是一类比较常见的问题,图片size过大导致,优化方法是适当降低图片清晰 度和限制大图缓存数量 5. 内存泄漏:OC对象、malloc内存块泄漏或者C++对象泄漏经过一定时间积累都会导致爆内 存
22. 手Q 爆内存闪退率优化效果 手Q外发版本SIGKILL闪退率 内存触顶工具上线 SIGKILL工具上线 WKWebView改造 大图片解码优化 7.0.0 7.1.0 7.3.0 7.6.0 7.6.5 7.7.0 7.7.8 7.8.2 7.8.8 7.9.0 7.9.5 8.0.0 8.0.5
23. 目录 1. App性能-移动终端的兵家必争之地 2. 卡顿优化-为App流畅度保驾护航 3. 内存优化-合理利用每一块内存 4. 节能省电-移动终端的独有挑战 5. 机器学习和大数据在性能监控的应用
24. 影响发热耗电的因素总结 手机由各种电子元器件组成,这些电子元器件在耗电的同 时,也会发热,与耗电主要因素总结如下: 1. CPU使用率:CPU的功耗是各种元器件中最高的,是引发发 热耗电的首要因素 2. 网络流量:信号较好时,Wifi和XG耗电量基本一致;信号较 差时,XG耗电量可达Wifi的12倍 3. GPS:GPS定位模块也是耗电大户,持续使用GPS定位1分 钟可引发发热 4. IO总量:IO设备的频繁使用会一定程度增加系统耗电 5. 屏幕亮度:屏幕亮度和耗电量成正比,当屏幕亮度最大时耗 电量是普通情况下的4倍 电量测试数据
25. 手Q iOS 发热耗电监控方案 监控方案总结: 1. 流量监控:在信令通道和Http通道建立 监控 CPU 1. 定时监控总CPU使 用率 2. 定时抓取高CPU线 程堆栈 统一监控机制,记录各业务流量 IO read/write fread/fwrite fgets/fputs fscanf/fprintf pread/pwrite Network send/sendto/sendmsg recv/recvFrom/recvmsg 2. GPS监控:GPS模块的权限统一管控,记 录各业务使用时长 3. CPU监控:CPU使用超过阀值时通过定 时抓取线程堆栈辅助分析 GPS Hook CLLocationManager 统计GPS定位时长 XG信号强度 1. 探测包统计 2. 客观因素,不属于 App问题 屏幕亮度 1. 定时获取 2. 客观因素,不属 于App问题 4. IO监控:大文件可直接抓取堆栈,频繁 文件读取结合CPU异常辅助分析 5. 其他:XG信号弱和屏幕亮度过亮导致的 发热问题属于客观因素,这类问题一般 无需跟进
26. CPU/IO异常堆栈监控策略 Thread 1 Thread 2 Thread 3 … Thread n Usage 1 Usage 2 Usage 3 … Usage n 辅助定位 CPU使用率 两分钟内平均CPU使用 率大于60% 调用栈 CPU问题定位策略: 堆栈抓取 调用栈 1.实时统计总CPU使用率 2.CPU总量异常时定时抓取 高CPU线程堆栈辅助分析 每分钟读写文件总量大于100Mb HOOK open/close read/write fread/fwrite fgets/fputs …… 大文件IO调用栈 总IO操作量 IO问题定位策略: 1.大文件IO直接抓取堆栈 2.IO总量异常定时抓取高 CPU线程堆栈辅助分析
27. 目录 1. App性能-移动终端的兵家必争之地 2. 卡顿优化-为App流畅度保驾护航 3. 内存优化-合理利用每一块内存 4. 节能省电-移动终端的独有挑战 5. 机器学习和大数据在性能监控的应用
28. 应用大数据静态检测代码耗时 数据库操作 NSUserDefualts AST分析 APM大数据 耗时接口提取 耗时系统方法 1. 获取主线程调用方法链 2. 分析主线程耗时方法 IO操作 …….. Codedog提单
29. 应用机器学习检测发热耗电问题 CPU XG流量 用户发热 反馈 过滤脏数据 实验室数据 提取APM资源 数据 GPS 训练 3层RNN神经 网络 归一化后 生成训练数据集 memory IO量 合流检测 分支合流性能 数据 训练好的RNN 神经网络模型
30. 组件开源:更极致的性能优化 爆内存监控组件: 已开源 (https://github.com/Tencent/OOMDetector) 卡顿+发热监控: Coming Soon.....