如何檢測或者優(yōu)化app的卡頓?
用instrument里面的time profiler
自己做一個檢測卡頓的小工具?(runloop)
https://juejin.im/post/6844903588712415239
RunLoop實際很簡單,它是一個對象,它和線程是一一對應(yīng)的,每個線程都有一個對應(yīng)的RunLoop對象,主線程的RunLoop會在程序啟動時自動創(chuàng)建,子線程需要手動獲取來創(chuàng)建
Runloop 和線程是綁定在一起的。每個線程(包括主線程)都有一個對應(yīng)的 Runloop 對象。我們并不能自己創(chuàng)建 Runloop 對象,但是可以獲取到系統(tǒng)提供的 Runloop 對象。
Runloop 和線程是綁定在一起的。每個線程(包括主線程)都有一個對應(yīng)的 Runloop 對象。我們并不能自己創(chuàng)建 Runloop 對象,但是可以獲取到系統(tǒng)提供的 Runloop 對象。
主線程的 Runloop 會在應(yīng)用啟動的時候完成啟動,其他線程的 Runloop 默認(rèn)并不會啟動,需要我們手動啟動
從源碼很容易看出,Runloop總是運行在某種特定的CFRunLoopModeRef下(每次運行__CFRunLoopRun()函數(shù)時必須指定Mode)。而通過CFRunloopRef對應(yīng)結(jié)構(gòu)體的定義可以很容易知道每種Runloop都可以包含若干個Mode,每個Mode又包含Source/Timer/Observer。每次調(diào)用Runloop的主函數(shù)__CFRunLoopRun()時必須指定一種Mode,這個Mode稱為 _currentMode,當(dāng)切換Mode時必須退出當(dāng)前Mode,然后重新進(jìn)入Runloop以保證不同Mode的Source/Timer/Observer互不影響。
CFRunLoopObserver是觀察者,可以觀察RunLoop的各種狀態(tài),并拋出回調(diào)。
RunLoop和線程的一一對應(yīng)的,對應(yīng)的方式是以key-value的方式保存在一個全局字典中
主線程的RunLoop會在初始化全局字典時創(chuàng)建
子線程的RunLoop會在第一次獲取的時候創(chuàng)建,如果不獲取的話就一直不會被創(chuàng)建
RunLoop會在線程銷毀時銷毀
source0是非基于Port的。只包含了一個回調(diào)(函數(shù)指針),它并不能主動觸發(fā)事件。使用時,你需要先調(diào)用 CFRunLoopSourceSignal(source),將這個 Source 標(biāo)記為待處理,然后手動調(diào)用 CFRunLoopWakeUp(runloop) 來喚醒 RunLoop,讓其處理這個事件。
Source1除了包含回調(diào)指針外包含一個mach port,Source1可以監(jiān)聽系統(tǒng)端口和通過內(nèi)核和其他線程通信,接收、分發(fā)系統(tǒng)事件,它能夠主動喚醒RunLoop(由操作系統(tǒng)內(nèi)核進(jìn)行管理
/* Run Loop Observer Activities */
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), //即將進(jìn)入run loop
kCFRunLoopBeforeTimers = (1UL << 1), //即將處理timer
kCFRunLoopBeforeSources = (1UL << 2),//即將處理source
kCFRunLoopBeforeWaiting = (1UL << 5),//即將進(jìn)入休眠
kCFRunLoopAfterWaiting = (1UL << 6),//被喚醒但是還沒開始處理事件
kCFRunLoopExit = (1UL << 7),//run loop已經(jīng)退出
kCFRunLoopAllActivities = 0x0FFFFFFFU
};