iOS卡顿监控方案浅析

2020/05/20 17:26
阅读数 1K

背景

最近,小编一直致力于解决一项性能问题,那就是iOS输入法输入卡顿问题的监控,通过一段时间的调研,小编整理出来了一些监控方法,这里就分享给大家,希望可以给正在进行这方面工作的测试同学一点帮助。



顿原因

首先,我们需要明确一个定义,就是卡顿是什么?

  • 死锁:主线程拿到锁A,需要获得锁B,而同时某个子线程拿了锁 B,需要锁A,这样相互等待就死锁了。

  • 主线程大量IO:主线程为了方便直接写入大量数据,会导致界面卡顿。

  • 主线程大量计算:算法不合理,导致主线程某个函数占用大量 CPU。

  • 大量的UI绘制:复杂的UI、图文混排等,带来大量的UI绘制。

  • 主线程等待其它线程:用户进行操作后其它线程进行较复杂计算导致结果没有迅速给到主线程进行页面刷新,用户就会存在等待情况造成卡顿反馈。



方案设计

针对以上问题,我们需要什么手段去进行排查呢?这里想到的就是将当前的线程栈进行捕捉,这样我们就可以找到当前卡顿在哪一行函数。所以,这里监控卡顿的整体思路就是起一个子线程,去监控你所需要关注的线程(例如主线程)的活动情况,如果发现有卡顿,就将当前堆栈dump下来。

上图可以看出,我们在这次监控卡顿的工具中主要监控的是线程RunLoop的超时情况,由于在iOS中线程的事件处理主要依靠的是RunLoop,如果单次RunLoop运行循环的事件超过某一时间,那就会产生出用户体验卡顿情况。正常RunLoop运行循环一次的流程如下所示:

从这个运行循环中可以看出,RunLoop休眠的事件是无法衡量的,处理事件的部分主要是在kCFRunLoopBeforeSources之后到kCFRunLoopBeforeWaiting之前和kCFRunLoopAfterWaiting之后和运行循环结束之前这两个部分。那我们重点监控时间也就是这两个部分的执行时间。接下来会为大家附上具体代码进行介绍。


具体方法

对于这两个部分的耗时监控,我们可以使用CFRunLoopObserverRef来对RunLoop的状态进行超时监测。

使用信号量dispatch_semaphore来控制对RunLoop状态判断的节奏,这个可以保证每个RunLoop状态的判断都会进行。对RunLoop状态的判断,我们专门在另外一个线程做判断。

这里我们使用了一个死循环在另一个线程中去监控待测线程的RunLoop状态,其中需要注意的是blockInterval是我们这边配置的卡顿阈值,如果设定200ms则填写200即可,如果超过阈值时间后,当前状态还是没有发生变化则会返回semaphore不等于0,此时我们会进行判断,如果当前的RunLoop状态为kCFRunLoopBeforeSources或kCFRunLoopAfterWaiting,则认为此时出现了线程卡顿,我们在超时的代码块中去填写需要执行的方法,例如内存堆栈的打印,卡顿次数的统计等等。









搜狗测试微信号:Qa_xiaoming

搜狗测试QQ粉丝群:459645679


本文分享自微信公众号 - 搜狗测试(SogouQA)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部