美文网首页乔帮主的遗产
使用RunLoop 进行卡顿监控

使用RunLoop 进行卡顿监控

作者: 再好一点点 | 来源:发表于2019-03-24 21:39 被阅读0次

在开发中,我们可以使用Xcode自带的Instruments工具的Core Animation来对APP运行流畅度进行监控,使用FPS这个值来衡量。这个工具我们只能知道哪个界面会有卡顿,无法知道到底是什么操作哪个函数导致的卡顿。

界面出现卡顿,一般是下面几种原因:

主线程做大量计算
主线程大量的I/O操作
大量的UI绘制
主线程进行网络请求以及数据处理
离屏渲染

监控界面卡顿,主要是监控主线程做了哪些耗时的操作,iOS中线程的事件处理依靠的是RunLoop,正常FPS值为60,如果单次RunLoop运行循环的事件超过16ms,就会使得FPS值低于60,如果耗时更多,就会有明显的卡顿。

正常RunLoop运行循环一次的流程是这样的:

SetupThisRunLoopRunTimeOutTimer();
do {
        __CFRunLoopDoObservers(kCFRunLoopBeforeTimers);
        __CFRunLoopDoObservers(kCFRunLoopBeforeSources);
  
        __CFRunLoopDoBlocks();
        __CFRunLoopDoSource0(); // 处理source0事件,UIEvent事件,比如触屏点击

        CheckIfExitMessagesInMainDispatchQueue(); // 检查是否有分配到主队列中的任务

        __CFRunLoopDoObservers(kCFRunLoopBeforeWaiting);
        var wakeUpPort = SleepAndWaitForWakingUpPorts(); // 开始休眠,等待ma ch_msg事件
        
        // mach_msg_trap
        // ZZz.....   sleep
        // Received mach_msg,  wake up
        
        __CFRunLoopDoObservers(kCFRunLoopAfterWaiting); // 被事件唤醒
        // Handle msgs
        if (wakeUpPort == timePort) { // 被唤醒的事件是timer
              __CFRunLoopDoTimers(); 
        } else if (wakePort == mainDispatchQueuePort) { // 主队列有调度任务
              __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__();
        } else { // source1事件,UI刷新,动画显示
              __CFRunLoopDoSource1();
        }
        __CFRunLoopDoBlocks();
} while (!stop && !timeout)

从这个运行循环中可以看出,RunLoop休眠的事件是无法衡量的,处理事件的部分主要是在kCFRunLoopBeforeSources之后到kCFRunLoopBeforeWaiting之前和kCFRunLoopAfterWaiting 之后和运行循环结束之前这两个部分
监控这两个部分的耗时,使用CFRunLoopObserverRef来监控RunLoop的状态:

首先创建observer

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

    __block NSInteger timeCount = 0;
    _semaphore = dispatch_semaphore_create(0);
    __weak typeof(self) weakSelf = self;
    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopAllActivities, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        weakSelf.myActivity = activity;
        dispatch_semaphore_signal(weakSelf.semaphore);
    });
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
然后开始检测卡顿情况:

需要注意的是,对卡顿的判断是通过kCFRunLoopBeforeSources或者kCFRunLoopBeforeWaiting这两个状态开始后,信号量+1,这时候信号量>0,dispatch_semaphore_wait不会阻塞,返回0,进行下一个while循环,如果此时还没有进入下一个RunLoop状态,此时信号量=0,dispatch_semaphore_wait就会在这里阻塞,到了设定的超时时间,dispatch_semaphore_wait的返回值>0,这时候就会进行耗时的判断。
我们可以自己设定超时时间和超过多少次算卡顿,这里设置超过250ms。


    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (true) {
            long count = dispatch_semaphore_wait(weakSelf.semaphore, 50 * NSEC_PER_MSEC); //50毫秒
            if (count != 0) {
                if (!observer) {
                    weakSelf.semaphore = NULL;
                    timeCount = 0;
                    return ;
                }
                
                if (weakSelf.myActivity == kCFRunLoopBeforeSources) {
                    if (++timeCount < 5) { //连续5次就是250毫秒
                        continue;
                    } else {
                        NSLog(@"卡顿了");
                    }
                }
            }
            timeCount = 0;
        }
    });

相关文章

  • 使用RunLoop 进行卡顿监控

    https://www.jianshu.com/p/17e545fe0ccb

  • 使用RunLoop 进行卡顿监控

    在开发中,我们可以使用Xcode自带的Instruments工具的Core Animation来对APP运行流畅度...

  • iOS通过runloop监控卡顿

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

  • 常规优化技巧

    卡顿优化 添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目的...

  • iOS常规的优化技巧

    原文地址 卡顿优化 添加Observer到主线程RunLoop中,通过监听RunLoop状态切换的耗时,以达到监控...

  • iOS使用RunLoop监控线上卡顿

    原文地址 通过iOS性能优化 我们知道,简单来说App卡顿,就是FPS达不到60帧率,丢帧现象,就会卡顿。但是很多...

  • 监控卡顿-Runloop

    1 对主线程Runloop注册一个回调函数runLoopObserverCallBack。在每次runloop的C...

  • Runloop监控卡顿

    一、监控卡顿的原理 1.1、原理 我们通过监听 NSRunLoop 的状态,就能够发现调用方法是否执行 时间过长,...

  • RunLoop监控app卡顿

    本文意义在分析如何利用runloop监控卡顿。代码可以看戴铭大佬的代码 思路 首先思路就是利用CFRunloopO...

  • iOS开发中的卡顿分析

    市面上的iOS卡顿分析方案有三种:监控FPS、监控RunLoop、ping主线程。 方案一:监控FPS 一般来说,...

网友评论

    本文标题:使用RunLoop 进行卡顿监控

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