造成App卡顿的一些原因
- 图片过多、过大,绘制图片耗时大
- 在主线程上执行一些耗时操作,如:网络请求
- 在主线程上做大量的IO操作
- 死锁、主线程和子线程抢锁
总而言之,只要主线程上任务耗时过长,无法及时响应用户操作或其他事件(或计时器)就是卡顿。
三方工具
https://github.com/Tencent/matrix
监听卡顿原理
既然是主线程上任务耗时过长导致的卡顿,那么我们就需要去监听主线程。而线程的消息事件是依赖于runLoop的,那么我们就需要去监听主线程对应的runLoop的状态。
卡顿即线程受阻,runLoop处于什么状态我们就可以认定为线程受阻呢?
1.runLoop进入睡眠前方法执行时间过长而导致无法进入睡眠
2.runLoop被唤醒后接受消息时间过长而无法进入下一步
所以kCFRunLoopBeforeSources和kCFRunLoopAfterWaiting这两个状态是需要监听的。
实现:
我们需要创建一个runLoop观察者,然后将此观察者添加到主线程对应的runLoop的common模式下,同时创建一个子线程用来定时监听主线程的runLoop状态。
代码:
//创建子线程监控
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//子线程开启一个持续的 loop 用来进行监控
while (YES) {
long semaphoreWait = dispatch_semaphore_wait(dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
if (semaphoreWait != 0) {
if (!runLoopObserver) {
timeoutCount = 0;
dispatchSemaphore = 0;
runLoopActivity = 0;
return;
}
//BeforeSources 和 AfterWaiting 这两个状态能够检测到是否卡顿
if (runLoopActivity == kCFRunLoopBeforeSources || runLoopActivity == kCFRunLoopAfterWaiting) {
//将堆栈信息上报服务器的代码放到这里
} //end activity
}// end semaphore wait
timeoutCount = 0;
}// end while
});
当监听到卡顿后我们就将堆栈信息记录下来并进行上报。
程序中认定卡顿的标准
可以设置一个时间阀值,如果超过了这个阀值就认定为卡顿。
网友评论