iOS App卡顿监控(Freezing/Lag)

栏目: IOS · 发布时间: 5年前

内容简介:使用CFRunLoopObserverRef,实时获得这些状态值的变化,如下:添加计算逻辑,如下:目击卡顿现场,记录此时的调用函数信息,作为卡顿证据。

iOS App卡顿监控(Freezing/Lag)

如何判断主线程卡顿:

监测NSRunLoop耗时情况。

NSRunLoop的调用主要在 kCFRunLoopBeforeSourceskCFRunLoopBeforeWaiting 之间,以及 kCFRunLoopAfterWaiting 之后。因此,若是发现这个两个时间内耗时过长,就可以判定此时主线程出现卡顿情况。

一、监控NSRunLoop状态变化

使用CFRunLoopObserverRef,实时获得这些状态值的变化,如下:

/// RunLoop状态观察回调
static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
    <#MyClass#> *object = (__bridge <#MyClass#>*)info;
    // 记录状态值
    object->activity = activity;
}
/// 注册RunLoop状态观察
- (void)registerRunLoopObserver {
    CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                                            kCFRunLoopAllActivities,
                                                            YES,
                                                            0,
                                                            &runLoopObserverCallBack,
                                                            &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
}

二、RunLoop耗时计算

另外开启一个线程,实时计算两个状态区域之间的耗时,是否达到阈值。

dispatch_semaphore_t 让子线程更及时地获知主线程NSRunLoop状态变化

卡顿覆盖范围: 多次连续小卡顿 单次长时间卡顿

添加计算逻辑,如下:

/// RunLoop状态观察回调
static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
    <#MyClass#> *object = (__bridge <#MyClass#>*)info;
    // 记录状态值
    object->activity = activity;
    
    // 发送信号
    dispatch_semaphore_t semaphore = object->semaphore;
    dispatch_semaphore_signal(semaphore);
}
/// 注册RunLoop状态观察,并计算是否卡顿
- (void) registerRunLoopObserver {
    CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
    CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                                            kCFRunLoopAllActivities,
                                                            YES,
                                                            0,
                                                            &runLoopObserverCallBack,
                                                            &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes);
    
    // 创建信号
    semaphore = dispatch_semaphore_create(0);
    
    // 在子线程监控时长
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        while (YES) {
            // 假定连续5次超时50ms认为卡顿(当然也包含了单次超时250ms)
            long st = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 50*NSEC_PER_MSEC));
            if (st != 0) {
                if (activity==kCFRunLoopBeforeSources || activity==kCFRunLoopAfterWaiting) {
                    if (++timeoutCount < 5) {
                        continue;
                    }
                    // 发现卡顿
                    NSLog(@"卡、卡、卡、顿、顿、了");
                }
            }
            timeoutCount = 0;
        }
    });
}

三、记录卡顿的函数调用

目击卡顿现场,记录此时的调用函数信息,作为卡顿证据。

此处,使用第三方Crash收集组件 PLCrashReporter ,它不仅可以收集 Crash信息 ,也可用于 实时获取各线程的调用堆栈 ,使用示例如下:

PLCrashReporterConfig *config = [[PLCrashReporterConfig alloc] initWithSignalHandlerType:PLCrashReporterSignalHandlerTypeBSD
                                                                   symbolicationStrategy:PLCrashReporterSymbolicationStrategyAll];
PLCrashReporter *crashReporter = [[PLCrashReporter alloc] initWithConfiguration:config];
NSData *data = [crashReporter generateLiveReport];
PLCrashReport *reporter = [[PLCrashReport alloc] initWithData:data error:NULL];
NSString *report = [PLCrashReportTextFormatter stringValueForCrashReport:reporter
                                                          withTextFormat:PLCrashReportTextFormatiOS];
NSLog(@"------------\n%@\n------------", report);

特别注意:

PLCrashReporter 虽然能提供较为准确的堆栈信息,用于定位问题,特别是使用符号化策略 PLCrashReporterSymbolicationStrategyAll

时,能够对堆栈信息进行符号化,但会消耗大量资源,需要占用较多时间,导致卡死现象(自测时,耗时超过7s,层多次到10s以上)。

不使用符号化策略 PLCrashReporterSymbolicationStrategyNone ,测试时,平均耗时也接近3s。

因此,加入该信息采集,需要特别注意,建议仅在开发调试阶段使用。

为了投入线上使用,还需要再想想如何解决该问题。

四、上报服务器

检测到卡顿,获取到调用堆栈信息,客户端再根据实际情况进行一定程度的过滤处理,将有价值的信息上报服务器。

后续对服务器收集到的数据进行分析,定位需要优化的功能逻辑。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

微信营销与运营

微信营销与运营

秦阳、秋叶 / 人民邮电出版社 / 2016-12-1 / 39.80

《微信营销与运营》共分七章。第1章重点介绍了微信营销的概念、价值和特征,引导读者全面认识微信营销;第2章介绍了个人微信号的运营技巧和手法;第3章重点介绍了微信公众平台的基础操作入门,申请适合自己的公众平台类型并进行基本设置;第4章介绍了微信运营的规划策略,落实公众号的定位、内容问题;第5章介绍微信运营中包括排版、增加粉丝、提升阅读量等运营实战中的经验和手法,并了解微信运营的整个运营框架体系;第6章......一起来看看 《微信营销与运营》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器