博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS App卡顿监控(Freezing/Lag)
阅读量:6975 次
发布时间:2019-06-27

本文共 4138 字,大约阅读时间需要 13 分钟。

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。

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

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

四、上报服务器

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

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

转载地址:http://idrsl.baihongyu.com/

你可能感兴趣的文章
LINUX学习(LINUX就该这么学)2
查看>>
PostgreSQL系列产品云生态、产品指南、企业全栈应用案例、开发管理实践
查看>>
linux内核启动_学习笔记
查看>>
linux下samba共享中文乱码解决办法
查看>>
HSRP热备份
查看>>
pfSense通过别名限制迅雷下载
查看>>
软件自动化测试资源列表
查看>>
数字签名与数字证书技术简介
查看>>
[LNMP]Nginx解析php与代理
查看>>
GridView动态添加新行
查看>>
使用Kazoo去增删改查zookeeper
查看>>
C# 实现系统关机、注销、重启、休眠、挂起
查看>>
SQL server 2000常用字符串长度总结
查看>>
征服Perl——哈希——里程碑M7
查看>>
遇到女神应该使用什么样的暗恋思维
查看>>
HA(heartbeat)主备模式实现lvs群集的高可用性
查看>>
mtr路由监控
查看>>
容器编排 Docker Compose
查看>>
KVM 使用virtio驱动Windows server 虚拟机
查看>>
我的Oracle 9i学习日志(15)-- 表的管理
查看>>