IOS中判断卡顿的方案总结
fps
fps (frames per second) 是图像领域中的定义,表示每秒渲染帧数,通常用于衡量画面的流畅度,每秒帧数越多,则表示画面越流畅,60fps 最佳,一般我们的app的fps 只要保持在 50-60之间,用户体验都是比较流畅的。
监测fps也有好几种,这里只说最常用的方案,我最早是在yyfpslabel中看到的。实现原理实现原理是向主线程的runloop的添加一个commonmodes的cadisplaylink,每次屏幕刷新的时候都要执行cadisplaylink的方法,所以可以统计1s内屏幕刷新的次数,也就是fps了,下面贴上我用swift实现的代码:
runloop
其实fps中cadisplaylink的使用也是基于runloop,都依赖main runloop。我们来看看
先来看看简版的runloop的代码
我们可以看到runloop调用方法主要集中在kcfrunloopbeforesources和kcfrunloopafterwaiting之间,有人可能会问kcfrunloopafterwaiting之后也有一些方法调用,为什么不监测呢,我的理解,大部分导致卡顿的的方法是在kcfrunloopbeforesources和kcfrunloopafterwaiting之间,比如source0主要是处理app内部事件,app自己负责管理(出发),如uievent(touch事件等,gs发起到runloop运行再到事件回调到ui)、cfsocketref。开辟一个子线程,然后实时计算 kcfrunloopbeforesources 和 kcfrunloopafterwaiting 两个状态区域之间的耗时是否超过某个阀值,来断定主线程的卡顿情况。
这里做法又有点不同,ios实时卡顿监控3 是设置连续5次超时50ms认为卡顿,戴铭在 gcdfetchfeed
4 中设置的是连续3次超时80ms认为卡顿的代码。以下是ios实时卡顿监控中提供的代码:
子线程ping
但是由于主线程的runloop在闲置时基本处于before waiting状态,这就导致了即便没有发生任何卡顿,这种检测方式也总能认定主线程处在卡顿状态。这套卡顿监控方案大致思路为:创建一个子线程通过信号量去ping主线程,因为ping的时候主线程肯定是在kcfrunloopbeforesources和kcfrunloopafterwaiting之间。每次检测时设置标记位为yes,然后派发任务到主线程中将标记位设置为no。接着子线程沉睡超时阙值时长,判断标志位是否成功设置成no,如果没有说明主线程发生了卡顿。anreye5中就是使用子线程ping的方式监测卡顿的。
以下是我用swift实现的:
cpu超过了80%
这个是matrix-ios 卡顿监控提到的:
我们也认为 cpu 过高也可能导致应用出现卡顿,所以在子线程检查主线程状态的同时,如果检测到 cpu 占用过高,会捕获当前的线程快照保存到文件中。目前微信应用中认为,单核 cpu 的占用超过了 80%,此时的 cpu 占用就过高了。
这种方式一般不能单独拿来作为卡顿监测,但可以像微信matrix一样配合其他方式一起工作。
戴铭在gcdfetchfeed中如果cpu 的占用超过了 80%也捕获函数调用栈,以下是代码:
卡顿方法的栈信息
当我们得到卡顿的时间点,就要立即拿到卡顿的堆栈,有两种方式一种是遍历栈帧,实现原理我在ios获取任意线程调用栈7写的挺详细的,同时开源了代码rcbacktrace,另一种方式是通过signal获取任意线程调用栈,实现原理我在通过signal handling(信号处理)获取任意线程调用栈写了,代码在backtrace-swift,但这种方式在调试时比较麻烦,建议用第一种方式。
以上就是ios中判断卡顿的方案总结的详细内容,更多关于ios卡顿检测的资料请关注其它相关文章!