美文网首页
iOS 进阶 (四) -- 卡顿监控

iOS 进阶 (四) -- 卡顿监控

作者: Q海龙 | 来源:发表于2019-08-09 15:37 被阅读0次

引发卡顿的几种原因

  • 复杂UI、图文混排的绘制量过大
  • 在主线程上做网络同步请求
  • 在主线程做大量的IO操作
  • 运算量过大,导致CPU持续高占用
  • 列锁和主子线程抢锁

对于卡顿监控,可能第一个想到的办法就是利用CADisplayLink去检测FPS值的变化,但这种方式不能满足我们对卡顿监控的需求。例如说,对于动画片来说,它的FPS是24,远远没有达到60的满帧,但是对于动画片来说,我们已经看的是很连贯的了,感觉不出来卡顿的现像,但24帧如果出现在App上,那可想而知,几乎卡的我们想杀掉App进程了吧。
其实用户所感知的卡顿主要就是来自主线程上的卡顿,因为我们要监控解决的也是这种情况。

利用RunLoop来监控卡顿

我们都知道,线程的消息事件是依赖于NSRunLoop的,所以从RunLoop入手,就能知道主线程上都做了哪些事,通过监听RunLoop状态,就能够发现调用方法是否执行时间过长,从而可以推断出是否出现了卡顿。
RunLoop主要的工作就是,有事要去处理时,保持线程忙,没事时让线程进入休眠。
RunLoop的状态

typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry , // 进入 loop
    kCFRunLoopBeforeTimers , // 触发 Timer 回调
    kCFRunLoopBeforeSources , // 触发 Source0 回调
    kCFRunLoopBeforeWaiting , // 等待 mach_port 消息
    kCFRunLoopAfterWaiting , // 接收 mach_port 消息
    kCFRunLoopExit , // 退出 loop
    kCFRunLoopAllActivities  // loop 所有状态改变
}

如果RunLoop的线程,进入睡眠前方法的执行时间过长而导致无法进入睡眠,或者线程唤醒后接收消息时间过长而无法进入下一步的话,就可以认为是线程受阻了,如果此时是在主线程上的话,表现出来的就是卡顿了。
所以,如果利用RunLoop来监控卡顿,就需要关注这两个阶段。进入睡眠之前和唤醒后的两个loop状态值,也就是kCFRunLoopBeforeSourceskCFRunLoopAfterWaiting(触发Source0回调和接收match_port消息两个状态)

监控的实现

首先需要创建一个RunLoop的观察者,方便我们检测RunLoop的状态

CFRunLoopObserverContext context = { 0, (__bridge void *)self, NULL, NULL};
runLoopObserver = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &runLoopObserverCallBack, &context);
CFRunLoopAddObserver(CFRunLoopGetMain(), runLoopObserver, kCFRunLoopCommonModes);

再将观察者runLoopObserver添加到主线程的RunLoopcommon模式下,然后再创建一个持续的子线程专门用来监控主线程的RunLoop状态
一旦发现状态为进入睡眠前的kCFRunLoopBeforeSources,或者唤醒后的kCFRunLoopAfterWaiting,如果在设置的时间内没有变化,即可判断为卡顿,然后dump出堆栈的信息,然后做进一步的分析

开启一个子线程监控:
// 创建子线程监控
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
});

相关文章

  • iOS通过runloop监控卡顿

    质量监控-卡顿检测iOS实时卡顿监控基于Runloop简单监测iOS卡顿的demo微信iOS卡顿监控系统iOS-R...

  • iOS 进阶 (四) -- 卡顿监控

    引发卡顿的几种原因 复杂UI、图文混排的绘制量过大在主线程上做网络同步请求在主线程做大量的IO操作运算量过大,导致...

  • 卡顿检测资料

    微信iOS卡顿监控系统 卡顿方案思考 卡顿检测 移动端监控体系之技术原理 iOS性能检测

  • Matrix-iOS 卡顿、内存监控 (一)

    Matrix-iOS 卡顿监控Matrix-iOS 内存监控 一、卡顿检测 Matrix-iOS 在addMoni...

  • iOS 卡顿监控

    界面卡顿是哪些问题导致的? 死锁:主线程拿到锁A,需要获得锁B,而同时某个子线程拿了锁B,需要锁A,这样互相等待就...

  • ios卡顿监控

    一般认为卡顿主要指主线程卡顿。针对 UI 卡顿或者说主线程卡顿可以有多种监控方案: 1、利用 CADisplayL...

  • Android 字节码插桩全流程解析

    在Android进阶宝典 -- Handler应用于线上卡顿监控[https://juejin.cn/post/7...

  • 性能

    微信iOS卡顿监控系统 wojteklu/Watchdog https://tech.meituan.com//p...

  • signal causes debugger to stop a

    问题:最近在做iOS UI卡顿监控,为了具体定位到卡顿的函数栈,使用到了pthread_kill,但是debug状...

  • iOS文章收录

    1、iOS如何监控界面卡顿掉帧,如何优化https://juejin.cn/post/69934852594676...

网友评论

      本文标题:iOS 进阶 (四) -- 卡顿监控

      本文链接:https://www.haomeiwen.com/subject/ouecjctx.html