卡顿主要表现为主线程卡死,不照应用户动作或许照应很慢,这种领会很差,会让用户对产品的认可度急速下滑,假定不及时优化,最终会导致用户丢失。

那么,哪些状况会导致主线程卡顿呢?大体有如下几个方面线程安全

  • 很杂乱的 UI 、图文混排的制造量很大;
  • 主线程进行网络同步央求;
  • 主线程上做许多的 IO 操作;
  • 运算量过大,CPU 持续高占用;
  • 死锁和主子线程抢锁。线程是什么意思

检测线程安全计划

为了优化卡顿,咱们需求精确的知道哪里发生了卡顿,然后才干有针对性的进行优化,所以在开始优化之前咱们需求去监控卡顿发生的当地。那么问题来了,怎样监控卡顿?

检测 FPS 改变崎岖是一种计划,但是并不推荐,原因我引用戴铭大佬在怎样运用 RunLoop 原理去监控卡顿线程和进程的差异是什么?一文中的描绘:”FPS 是一秒显现的帧数,也便是一秒内画面改变数量。假定按照动画片来说,动画片的 FPS 便是 24,是达不到 60 满线程和进程的差异是什么帧的。也便是说,关于动画片来说,24 帧时虽然没有 60 帧时流转,但也已经是连接的了,所以并不能说 24 帧时就算是卡住了。“

另一种推荐的计划便是 RunLoop。为什么Runloop能够做到卡顿监控?咱们知道程序中的使命都是在线程的几种状况线程中实施,而线程依赖于 RunLoop,而且RunLoop总是在相应的状况下实施使命,实施结束以后会切换到下一个状况,假定在一个状况下线程池创立的四种实施时间过长导致无法进入下一个状况就能够线程池以为发生了卡顿,产品设计工作方向所以能够依据主线程 RunLoop 的状况改变检动画片猫和老鼠动画片少儿小猪佩奇使命实施时间是否太长。至于多长时间算作卡顿能够依据自己的需动画片猫和老鼠求来设置,一般状况下能够设置1秒钟作为阀值。

RunLoop 的状况如下:

typapp下载edef CF_OPTIONS(CFOp开源tionFlags, CFRunLoopActivity) {
kC动画片少儿小猪佩奇FRunLoopEntry = (1UL << 0), // 进入Runloop
kCFRunLoopBeforeTimers = (1UL << 1), // 处理Timer工作
kCFRunLoopBefo产品reSources = (1UL << 2), // 处理Source工作
kCFRunLoopBeforeWaiting = (1UL &产品生命周期lt;< 5), // 进入休眠
kCFRunLoopAft产品生命周期erWaiting = (1UL << 6), // 唤醒
kCFRunLoopEx开源阅览app下载安装it = (1UL << 7), // 退出Runloop
k线程池面试题CFRunLoopAl产品lActivities = 0x0FFFFFFF开源众包U // 一切状况
};

RunLoop 的实施流程:

RunLoop卡顿监控

在一次循环中,Timer工作、S动画大放映ource工作、唤醒后工作假定处理动画制造软件时间过长都能够以为卡顿了;当然还有一种休眠前的事app下载情,但是监控这个工作时需求特别留神,由于不能把休眠的时间算作是卡顿的。

详细结束

大体的思路有了,那怎样来结束呢?要监控 RunLoop 工作,首要需求一个查询者:

CFRunLoopObserverContext context = {
0, // 直接传0就好
(__bridge void*)self, // 对应回调中当地 void *info 参数
&amp动画片少儿;CFRetain, // 内存处理计划
&CFR产品运营elease, // 内存处理计划
NULL
};
observer线程池的七个参数 = CFRunLoopObserv开源节流erCreate(kCFAllocatorDefault, kCFRunLoopAllActivi开源矿工ties, YES, 0, &runloopObserverCallback, &coappreciatentext);

查询主线程:

CFRunL开源软件oopAddObserver(CFRunLoop开源是什么意思GetMain(), obs动画制造软件erver, kCFR开源代码网站githubunLoopCommonModes);

在回调函数中,需求记录下其时开源代码网站github的方法以便于后边检测使命的处理:

static void runloopObserverCallback(CFRunLoop开源阅览app下载安装ObserverRef observer, CFRunLoopActivity activity, voi产品司理d *info) {
[LagMonitor sha开源red]->currentActivity = activi产品司理ty;
dispatch_semaphore_t sema = [LagMonitor shared]->semaphore产品运营;
dispatch_semaphore_signal(sema);
}开源软件

然后,不能在主线程中进行查询使命,由于咱们观测的是主线程自身的使命,把查询后的处理使命也加到主线程会使得开源阅览app下载安装主线程使命不朴实,影响检测成果的精确性。所以,咱们在子线程中处理检测使命,相应动画片汪汪队的代码和释义如下:

// 在子线程中监控卡顿
semaphore = dispatch_semaphore_create(0);
dispatch_async(d产品设计工作方向ispatch_get_glo产品设计工作方向bal_queue(0, 0), ^{
// 打开持续线程池面试题的loop来监控
while ([LagMonitor shaappearred]-&线程撕裂者gt;isM动画制造软件onitoring) {
if ([La开源代码网站githubgMonit开源代码网站githubor shared]->currentActivity == kCFRunLoopBefo动画大放映reWaiting)
{
// 处理休眠前工作观测
__block BOOL timeOut = YES;
dispatc开源节流h_async(dispatch_get_main_queue()开源, ^{
timeOut = NO; // timeOut使命
});
[N开源阅览app下载安装SThread sleepForTimeInterva产品l:WAIT_TIME];
// WAIT_T线程池IME 时间后,假定 tim动画片猫和老鼠eOut使命app下载 任未实施, 则以为主线程前面的使命实施时间过长导致卡顿
if (timeOuappeart) {
[LXDBacktraceLogger lxd_logMain]; // 输出库房信息
}
}
else
{
// 处理 Timer,Source,唤醒后工作
//动画头像 同步等候时间内,接收到信号result=0, 超时则持续往下实施而且result!=0
long r动画片少儿小猪佩奇esult = dispatch_semaphore_wait([LagM线程安全onitor shared]->semaphore, dispatchapproach_time(DISapp下载PATCH_TIME_NOW, OU产品设计工作方向T_TIME));
if (result != 0) { // 超时
if (![LagMonitor shared]->observer) {
[[LagMonitor shared] endMonitor];
continue;
}
if ([LagMonitor shared]->currentActivity == kCFRunLoopBeapp是什么意思foreSources ||
[LagMonitor shared]->currentActivity == kCFRunLoopAfterWaiting  ||
[LagMoniappletor shared]产品艺术设计-&开源我国gt;currentActivity =动画片猫和老鼠= kCFRunLoopBeforeTimers) {
[LXDBacktraceLogger lxd线程安全_logMain]; // 输线程的几种状况出库房信息
}
}
}
}
})线程的几种状况;

项目的悉数代码都在 这儿 ,其间 [LXDBacktraceLogger lxd_logMain] 运用了 LXDAppF线程撕裂者luecyMonitor 中的开源代码输出库房信息。

检测效果

咱们开源节流什么意思运转看产品质量法一下效果,首要调用

[[LagMonitor shared] beginMonitor];

查看日志输出:

runloop卡顿监控[45103:2594859]动画片少儿小猪佩奇 touchesBegan
runloop卡顿监控[45103:2595184] 主线程卡顿 Backtrace of Thread 771:
======================================================================================
libsystem_kernel.dylib         0x7fff5eapp是什么意思703756 __semwait_signal + 10
F开源矿工oundation                     0x7fff2085188c +[NSThread slee线程pForTimeInterval:] + 170
runloop            0x107bbde06 -[ViewController touchesBegan:withEvent:] + 118
UapplicationIKitCore                      0x7fff246a8b63 forwardTouchMethod + 321
UIKitCore                      0x7fff246a8a1开源是什么意思1 -[UIRes开源软件ponder touchesBegan:withEvent:] + 49
UIKitCore                      0x7fff246b7ad1 -[U线程安全IWindow _sendTouchesForEvent:] + 622
UIKitCore                      0x7fff246b9be3 -[UIWindow sendEvent:] + 4774
UIKitCore                      0x7fff246938f6 -[UIApplication sendEvent:] + 633
UIKitCore                      0x动画大放映7fff2472439c __processEventQueue + 13895
UIKitCore                      0x7fff线程和进程的差异是什么2471ad0f __eventFetcherSourceCallback + 104
CoreFoundation                 0x7fff203动画片小猪佩奇全集播映8c37a __CFRUNLOOP_IS_CALLING_OUT_TO_A_SO

日志显现,在 -[ViewController touchesBegan:withEvent:] 中有+[NSThread sleepForTimeInterval:] 发生了卡顿,回到项目中查看代码:

- (void)touchesBe动画片少儿小猪佩奇gan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"touchesBega动画片小猪佩奇全集播映n");
[NSThrapp是什么意思ead s开源矿工leepForTimeInterval:2];
}

与日志契动画合,这儿的确发生了卡顿,就能够有针对性的进行优化。

项目地址:runloop卡顿监控

参考资料

深化了解RunLoop,ibireme

怎样运用 RunLoop 原理去监控卡顿?,戴铭

LXDAppFluecyMonitor