FPS
CADisplayLink允许我们注册一个与刷新信号同步的回调处理。可以通过屏幕刷新机制来展示fps值。
问题:
- 回调总是需要cpu空闲才能处理,无法及时采集调用栈信息。
- 监听屏幕刷新会频繁唤醒 runloop,闲置状态下有一定的损耗
子线程Ping
使用子线程定时向主线程中仍入空任务,超过指定时间任务未被执行则判定为卡顿。
问题
- ping之间存在漏查情况。
- 会不停的唤醒主线程runloop,有一定损耗。
RunLoop
基于runloop检测,使用子线程实时检测runloop状态,执行超过指定时间则判定为卡顿。
问题:
- 捕获到的卡顿堆栈,不一定是最耗时的任务。不过最耗时任务有较大的概率被捕获到。
- 在一些复杂的页面下,卡顿的产生并不一定是某个耗时大任务,可能是由于多个耗时小任务共同作用。在这种case下,runloop检测方式很难帮助我们解决界面的卡顿问题。
hook objc_msgSend
借助fishhook对objc_msgSend、objc_msgSendSuper进行hook,在方法开始执行和结束执行插入代码,从而获取堆栈和每个方法的耗时。设置一定的阈值,将耗时方法提取出来。
问题:
扫描二维码关注公众号,回复:
13681504 查看本文章
- 需要写汇编来进行hook,实现成本相对较高。
- 插入的代码执行频率较高。可以通过一定手段进行优化
- 只对主线程上的调用进行操作
- 对有一定耗时的方法进行记录
- 对分配的queue、stack内存空间进行复用,避免频繁申请和释放。
简单总结
实现成本 | 性能损耗 | 堆栈价值 | |
---|---|---|---|
FPS | 简单 | 屏幕刷新会频繁唤醒 runloop | 无 |
Ping | 简单 | 会不停的唤醒主线程runloop | 中 |
Runloop | 中等 | 低 | 中 |
TimeProfiler | 较复杂 | 插桩代码调用频繁 | 高 |