卡顿监控 红框里才是真正的判断
1、即将要睡眠 2、即将要运行(唤醒)
第一个 Observer 的 order 调整到 LONG_MIN
进入 kCFRunLoopAfterWaiting 状态时,第一个被调用,用于监控 Runloop 处于 运行状态
第二个 Observer 的 order 调整到 LONG_MAX
进入 kCFRunLoopBeforeWaiting 状态时,最后一个被调用,用于判断 Runloop 处于 睡眠状态
如下图所示,通过 双 Observer ,我们可以更加准确的判断Runloop 的运行状态,从而对卡顿进行更加有效的监控。
为了调整回调的执行顺序,我们需要先了解 __CFRunLoopDoObservers
函数的执行逻辑。
/* rl is locked, rlm is locked on entrance and exit */
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) __attribute__((noinline));
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */
cf_trace(KDEBUG_EVENT_CFRL_IS_DOING_OBSERVERS | DBG_FUNC_START, rl, rlm, activity, 0);
CHECK_FOR_FORK();
// 获取 runLoopMode 的 observer 数量,如果小于1,则直接返回
CFIndex cnt = rlm->_observers ? CFArrayGetCount(rlm->_observers) : 0;
if (cnt < 1) return;
/* Fire the observers */
STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1);
CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : (CFRunLoopObserverRef *)malloc(cnt * sizeof(CFRunLoopObserverRef));
CFIndex obs_cnt = 0;
// 1、顺序遍历 _observers,
// 因为每个 observer 可以观察不同的 activity,所以,需要通过 & 操作符过滤需要触发的 observer
// 并组成新的数组 collectedObservers
for (CFIndex idx = 0; idx < cnt; idx++) {
CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
// 【避免递归】1、通过 __CFRunLoopObserverIsFiring 判断是否处于执行状态
if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) {
collectedObservers[obs_cnt++] = (CFRunLoopObserverRef)CFRetain(rlo);
}
}
__CFRunLoopModeUnlock(rlm);
__CFRunLoopUnlock(rl);
// 2、顺序遍历 collectedObservers
for (CFIndex idx = 0; idx < obs_cnt; idx++) {
CFRunLoopObserverRef rlo = collectedObservers[idx];
__CFRunLoopObserverLock(rlo);
if (__CFIsValid(rlo)) {
// 【非重复 observer】1、记录是否属于非重复 observer
Boolean doInvalidate = !__CFRunLoopObserverRepeats(rlo);
// 【避免递归】2、回调前,通过 __CFRunLoopObserverSetFiring 记录执行的状态
__CFRunLoopObserverSetFiring(rlo);
__CFRunLoopObserverUnlock(rlo);
CFRunLoopObserverCallBack callout = rlo->_callout;
void *info = rlo->_context.info;
cf_trace(KDEBUG_EVENT_CFRL_IS_CALLING_OBSERVER | DBG_FUNC_START, callout, rlo, activity, info);
// 3、执行 observer 的回调
__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(callout, rlo, activity, info);
cf_trace(KDEBUG_EVENT_CFRL_IS_CALLING_OBSERVER | DBG_FUNC_END, callout, rlo, activity, info);
// 【非重复 observer】2、非重复 observer,在回调完毕后,直接销毁
if (doInvalidate) {
CFRunLoopObserverInvalidate(rlo);
}
// 【避免递归】3、回调后,通过 __CFRunLoopObserverUnsetFiring 恢复状态
__CFRunLoopObserverUnsetFiring(rlo);
} else {
__CFRunLoopObserverUnlock(rlo);
}
CFRelease(rlo);
}
__CFRunLoopLock(rl);
__CFRunLoopModeLock(rlm);
if (collectedObservers != buffer)
free(collectedObservers);
cf_trace(KDEBUG_EVENT_CFRL_IS_DOING_OBSERVERS | DBG_FUNC_END, rl, rlm, activity, 0);
}
__CFRunLoopDoObservers 会先遍历 _observers ,并根据各种条件组成一个新的数组 collectedObservers
新的数组生成后,会再次遍历 collectedObservers,并通过 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ 回调监控函数
得到第一个重要的结论:通过控制 _observers 数组的排列顺序,能够改变调用时机。
CFRunLoopAddObserver
函数内部会根据 CFRunLoopObserverRef
的 _order
逆序遍历 CFRunLoopRef
的 _observers
,并找到合适的位置进行插入
具体的源码如下所示:
// 添加 observer
void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) {
CHECK_FOR_FORK();
CFRunLoopModeRef rlm;
// 如果 runloop 处于销毁状态,直接返回
if (__CFRunLoopIsDeallocating(rl)) return;
// 如果主线程已经停止执行,则直接返回
if (__CFMainThreadHasExited && rl == CFRunLoopGetMain()) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
CFLog(kCFLogLevelError, CFSTR("Attempting to add observer to main runloop, but the main thread has exited. This message will only log once. Break on _CFRunLoopError_MainThreadHasExited to debug."));
});
_CFRunLoopError_MainThreadHasExited();
return;
}
// 合规性校验 & 防止重入
if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return;
__CFRunLoopLock(rl);
// 1、如果监听 kCFRunLoopCommonModes,则遍历 _commonModes,并进行监听
if (modeName == kCFRunLoopCommonModes) {
CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL;
if (NULL == rl->_commonModeItems) {
rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks);
}
CFSetAddValue(rl->_commonModeItems, rlo);
if (NULL != set) {
CFTypeRef context[2] = {rl, rlo};
/* add new item to all common-modes */
CFSetApplyFunction(set, (__CFRunLoopAddItemToCommonModes), (void *)context);
CFRelease(set);
}
} else {
rlm = __CFRunLoopFindMode(rl, modeName, true);
if (NULL != rlm && NULL == rlm->_observers) {
rlm->_observers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
}
if (NULL != rlm && !CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo)) {
Boolean inserted = false;
// 2、逆序遍历 _observers,并找到合适的位置进行插入
for (CFIndex idx = CFArrayGetCount(rlm->_observers); idx--; ) {
CFRunLoopObserverRef obs = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx);
if (obs->_order <= rlo->_order) {
CFArrayInsertValueAtIndex(rlm->_observers, idx + 1, rlo);
inserted = true;
break;
}
}
if (!inserted) {
CFArrayInsertValueAtIndex(rlm->_observers, 0, rlo);
}
rlm->_observerMask |= rlo->_activities;
__CFRunLoopObserverSchedule(rlo, rl, rlm);
}
if (NULL != rlm) {
__CFRunLoopModeUnlock(rlm);
}
}
__CFRunLoopUnlock(rl);
}
参考:
原文:https://blog.csdn.net/sinat_35969632/article/details/111351356
matrix/WCBlockMonitorMgr.mm at master · Tencent/matrix · GitHub
打不开可以试着把 github.com替换为hub.fgit.ml