iOS性能监控

iOS性能监控

背景

移动互联网的增长红利已经结束,如何运营好存量用户也变得越来越重要。而随着随着移动互联网的不断发展,用户也越来越关心应用的体验。随着业务不断快速迭代,复杂度不断增加,应用的性能问题势必会随之积累。而在传统的开发流程中,通常需要:线上用户反馈 -> 分析问题原因 -> 解决性能问题 -> 验证等4步。我们必须思考,如何快速发现并解决日渐复杂的业务导致的功能不断迭代所产生的性能问题。近两年,APM技术快速发展,国内厂商更是百花齐放。最近对APM技术做了一个调研,希望以此文章作为一个总结,以加深认识。

APM

AMP即 Application Performance Manager,定位于帮助开发团队快速精确地定位性能问题,进而推动应用的性能和用户体验的提升。那么APM关心的性能指标都有哪些呢?如下所示:

  • 界面卡顿、卡顿堆栈
  • 网络请求:成功率、状态码、流量、网络响应时间、HTTP与HTTPS的 DNS 解析、TCP握手、SSL握手(HTTP除外)、首包时间等时间
  • 交互监控:页面加载时间
  • 启动时间
  • 崩溃率、崩溃堆栈
  • Abort 率:也就是由于内存过高的等原因,被系统杀死的情况
  • 其他:内存、帧率、CPU使用率、启动时间、电量等

性能指标如何采集?数据的采集最好尽量避免侵入业务代码,业务无感知的情况下完成采集工作,所以做好的方式是面向切面编程。
有了性能日志后,还需要对数据进行分析并定位问题。
整体APM流程如下图所示:

实现原理

卡顿监控方案:

  1. FPS监控:通过监控一段连续的FPS计算丢帧率来衡量页面流畅性。

  2. 主线程监控:开辟一个子线程检测主线程RunLoop,当kCFRunLoopBeforeSources与kCFRunLoopAfterWaiting这两个状态间的耗时超过阈值时,就记为一次卡顿

  3. 综合监控:由于FPS与主线程卡顿监控容易发生抖动,业界又提出了一种综合方案,结合主线程监控、FPS监控、以及CPU等,作为卡顿的综合判断标准。

卡顿日志采集上报: 参考PLcrashreporter,构造crash.log日志上报,结合符号表文件进行符号化

网络监控

方案1:继承NSURLProtocol 拦截Http请求

方案2:方法替换,动态代理,针对NSURLSession、NSURLConnection

方案3:使用fishhook库hook CFNetwork

冷启动时间

t(App 总启动时间) = t1(main()之前的加载时间) + t2(main()之后的加载时间)。

t1 = 系统的 dylib (动态链接库)和 App 可执行文件的加载时间

下面的步骤构成了 t1 的时间线:

Load dylibs -> Rebase -> Bind -> ObjC -> Initializers

t1比较难统计,目前业界的方案是在+load方法中打点统计,也就是上文时间线的Objc setUp阶段开始统计,但是这种方式是不够精确的。而且t1的大头其实是在Load dylibs阶段。目前只能通过xcode配置,在控制台打印的方式来统计。

t2 = main函数执行之后到 AppDelegate 类中的applicationDidFinishLaunching:withOptions:方法执行结束前这段时间

页面响应时间

hook ViewController的生命周期

崩溃率

Abort率

目前对于内存过高被杀死的情况是没有办法直接统计的,一般通过排除法来做百分比的统计,原理如下

  • 程序启动,设置标志位
  • 程序正常退出,清楚标志
  • 程序Crash,清楚标志
  • 程序电量过低导致关机,这个也没办法直接监控,可以加入电量检测来辅助判断
  • 第二次启动,标志位如果存在,则代表Abort一次,上传后台做统计

其他性能数据监控:FPS、CPU使用率、内存占用