内容简介:使用CFRunLoopObserverRef,实时获得这些状态值的变化,如下:添加计算逻辑,如下:目击卡顿现场,记录此时的调用函数信息,作为卡顿证据。
iOS App卡顿监控(Freezing/Lag)
如何判断主线程卡顿:
监测NSRunLoop耗时情况。
NSRunLoop的调用主要在 kCFRunLoopBeforeSources
和 kCFRunLoopBeforeWaiting
之间,以及 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。
因此,加入该信息采集,需要特别注意,建议仅在开发调试阶段使用。
为了投入线上使用,还需要再想想如何解决该问题。
四、上报服务器
检测到卡顿,获取到调用堆栈信息,客户端再根据实际情况进行一定程度的过滤处理,将有价值的信息上报服务器。
后续对服务器收集到的数据进行分析,定位需要优化的功能逻辑。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- zabbix监控tomcat 自定义监控项
- iOS 性能监控(一)—— CPU功耗监控
- iOS 性能监控(二)—— 主线程卡顿监控
- WGCLOUD 监控系统更新,集成 ES 在线监控工具
- 监控之路5-zabbix定义一次完整的监控
- WGCLOUD 监控系统更新,进程监控模块 bug 修复
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。