奇技指南

本文介绍360在iOS端移动端线上性能监控方案——QDAS-APM。




iOS本地性能监控方案 iphone性能监控工具_ios开发网卡监控


01 背 景

app的性能问题是影响用户体验的重要因素之一。性能问题主要包含:崩溃、网络请求错误或者超时、UI响应速度慢、主线程卡顿、CPU和内存使用高、耗电量大等等。大多问题的原因在于开发者错误地使用了线程、锁、系统函数、编程规范问题、数据结构等等。解决这个问题的关键在于尽早发现和定位问题。

360作为一家注重用户体验的公司,app的性能问题无疑是被重点关注的,我们也总结出了一套自己的app性能监控体系。在平时开发和用户反馈的问题中,我们对性能问题进行了归纳,总结出了5个分别是:资源文件如何掌控、 版本质量如何保证、线上问题如何排查、开发阶段如何防止性能衰减、性能监控是否能真实反映用户体验。同时学习了业内相对完善的性能监控平台上的功能原理。从而得出了360在iOS端移动端线上性能监控方案——QDAS-APM。

02 功能和原理

QDAS-APM已经实现以下功能监控:

  • 页面渲染时长
  • 主线程卡顿
  • 网络错误
  • FPS
  • 大文件存储
  • CPU
  • 内存使用
  • Crash
  • 启动时长

下面按照功能详细介绍实现细节和原理。另外用户在使用app时会感知性能问题,我们可以将其转化为具体的性能监控指标。

1、页面渲染时长

什么是页面渲染时长?页面渲染时长其实是从页面初始化到用户能看到页面效果的时间长度。所要了解的指标有:

  • 生命周期系统方法执行时长
  • 页面类名
  • 启动类型
  • 执行耗时
  • 插件名称

关键度量的指标是执行耗时,不同的方法和步骤产生的耗时在用户能接受的范围内才被认为是合理。其他指标则是起有关联性作用和定位问题。直接hook UIViewController的方法明显是不可行的,原因是它只作用在UIViewController的方法,而app中大部分都采用继承UIViewController的方式。


iOS本地性能监控方案 iphone性能监控工具_子类_02


这里列出两个可行性方案:

  1. 采用KVO,我们知道对于任意对象进行KVO操作时,系统都会帮你动态的创建一个复制类,同时实现了setter getter函数的覆盖和函数实现。
  2. 采用runtime遍历所有类为UIViewController的子类,再进行动态替换。

这两种方式更加推荐第一种,出于对兼容性、性能、以及能够直接获取UIViewController的子类的IMP。那具体如何实现呢?总结归纳为三步骤:

  1. 需要创建一个UIViewController的类别,对UIViewController的实例进行KVO,目的是让KVO创建需要监控UIViewController的子类。
  2. 添加需要监控的方法,在KVO创建出来的子类添加需要Swizzle的方法对应的SEL及其IMP。目的是控制调用原来类的方法时机。
  3. 在UIViewController的实例销毁时,在dealloc方法里将KVO监听移除,不然会导致Crash。

举个例子:我们以监控到qh_viewDidLoad方法举例:

static void qh_viewDidLoad(UIViewController *kvo_self, SEL _sel){ Class kvo_cls = object_getClass(kvo_self); Class origin_cls = class_getSuperclass(kvo_cls); // 注意点 IMP origin_imp = method_getImplementation(class_getInstanceMethod(origin_cls, _sel)); void(*func)(UIViewController *, SEL) = (void(*)(UIViewController *, SEL))origin_imp; CFAbsoluteTime startTime = CACurrentMediaTime(); func(kvo_self, _sel); CFAbsoluteTime endTime = CACurrentMediaTime(); NSTimeInterval duration = (endTime - startTime)*1000; NSLog(@"Class %@ cost %g in viewDidLoad