Matrix中WCBlockMonitorMgr 类详解以及流程
概述
WCBlockMonitorMgr 是微信开源性能监控框架 wechat-matrix 中用于监控 iOS/macOS 应用主线程卡顿(Block)和 CPU 高使用率的核心管理类。它通过监听主线程 RunLoop 状态,周期性采样调用栈,判断卡顿事件并触发回调,最终生成性能分析报告。该类设计了高效的监控线程,支持多种平台特性和动态配置,具备丰富的回调接口,方便集成和扩展。
目录
涉及到的相关模块
- 依赖微信Matrix 框架内部多个模块,如:
WCMainThreadHandler(调用栈管理)WCCPUHandler(CPU 使用率处理)WCDumpInterface(卡顿报告生成)WCPowerConsumeStackCollector(耗电堆栈采集)WCBlockMonitorConfigHandler(配置管理)WCFilterStackHandler(卡顿事件过滤)- 以及日志、设备信息等辅助模块。
CPU 频率测量
- 仅在 ARM64 架构下实现,利用汇编指令循环计数结合 mach 时间戳,估算 CPU 频率。
- 通过多次测量取中位数,保证稳定性。
- 返回 CPU 频率的单位为 GHz。
全局静态变量说明
| 变量名 | 说明 |
|---|---|
g_RunLoopTimeOut | 主线程 RunLoop 卡顿阈值,单位微秒,默认值由配置控制。 |
g_CheckPeriodTime | 检测周期时间,单位微秒,通常为阈值的一半。 |
g_CPUUsagePercent | CPU 使用率阈值,超过该值认为 CPU 过高。 |
g_PerStackInterval | 单次调用栈采样间隔,单位微秒,默认约 50ms。 |
g_StackMaxCount | 单次调用栈最大采样帧数。 |
g_bSensitiveRunloopHangDetection | 是否启用敏感的 RunLoop 卡顿检测(iOS 11+)。 |
g_CurrentThreadCount | 当前线程数统计。 |
g_MainThreadHandle | 是否启用主线程调用栈采样。 |
g_MainThreadProfile | 是否启用主线程调用栈性能分析。 |
g_MainThreadCount | 一轮检测中采样调用栈的次数。 |
g_PointMainThreadArray | 当前主线程调用栈快照数组指针。 |
g_PointMainThreadRepeatCountArray | 调用栈重复计数数组。 |
g_PointMainThreadProfile | 主线程调用栈性能分析数据。 |
g_PointCPUHighThreadArray | CPU 使用率高线程调用栈快照数组。 |
g_PointCpuHighThreadCount | CPU 高线程数量。 |
g_PointCpuHighThreadValueArray | CPU 高线程对应的 CPU 使用率数组。 |
g_thermalState | iOS 11+ 设备热状态。 |
g_tvRun | RunLoop 最近运行时间戳。 |
g_bRun | RunLoop 是否处于运行状态标志。 |
g_lastCheckTime | 上次检测时间戳。 |
g_bLaunchOver | 应用启动是否完成标志。 |
g_bBackgroundLaunch | 是否为后台启动。 |
类接口与属性
@interface WCBlockMonitorMgr : NSObject <WCPowerConsumeStackCollectorDelegate>
@property (nonatomic, weak) id<WCBlockMonitorDelegate> delegate;
@property (nonatomic, strong) WCBlockMonitorConfigHandler *monitorConfigHandler;
#if TARGET_OS_OSX
@property (nonatomic, strong) NSApplicationEvent *eventHandler;
#endif
+ (WCBlockMonitorMgr *)shareInstance;
- (void)resetConfiguration:(WCBlockMonitorConfiguration *)bmConfig;
- (void)start;
- (void)stop;
// iOS 特有:后台启动及挂起处理
- (void)handleBackgroundLaunch;
- (void)handleSuspend;
// CPU 监控控制
- (void)startTrackCPU;
- (void)stopTrackCPU;
- (BOOL)isBackgroundCPUTooSmall;
// RunLoop 阈值动态调整
- (BOOL)setRunloopThreshold:(useconds_t)threshold;
- (BOOL)lowerRunloopThreshold;
- (BOOL)recoverRunloopThreshold;
// 是否挂起所有线程
- (void)setShouldSuspendAllThreads:(BOOL)shouldSuspendAllThreads;
// 自定义卡顿报告生成
- (void)generateLiveReportWithDumpType:(EDumpType)dumpType withReason:(NSString *)reason selfDefinedPath:(BOOL)bSelfDefined;
// 获取当前卡顿报告自定义用户信息
- (NSDictionary *)getUserInfoForCurrentDumpForDumpType:(EDumpType)dumpType;
#if TARGET_OS_OSX
+ (void)signalEventStart;
+ (void)signalEventEnd;
#endif
@end
核心功能详解
单例获取与初始化
- 使用 GCD
dispatch_once保证单例线程安全。 - 初始化时创建异步串行队列,设置默认停止状态。
- 释放时释放 RunLoop 观察者,移除通知监听,释放调用栈缓存。
配置管理
- 通过
resetConfiguration:方法注入配置对象WCBlockMonitorConfiguration。 - 配置包括卡顿阈值、CPU 使用率阈值、采样间隔、是否打印日志、是否启用耗电堆栈采集等。
- 配置会影响内部静态变量和监控参数。
启动与停止监控
start方法初始化参数,添加 RunLoop 观察者,创建监控线程并启动。- 监听应用生命周期通知(iOS),如进入后台、激活、终止等,调整监控策略。
stop方法停止监控线程,移除 RunLoop 观察者,等待监控线程退出。
RunLoop 观察者管理
- 通过
CFRunLoopObserverCreate创建两个观察者,分别监听 RunLoop 入口和退出阶段。 - 观察者回调更新全局运行状态
g_bRun和时间戳g_tvRun。 - 支持普通模式和初始化模式(iOS UIInitializationRunLoopMode)。
- 在敏感模式下,RunLoop 即将等待时检测卡顿。
监控线程主循环
- 监控线程执行
threadProc方法,循环检测卡顿。 - 先睡眠启动延迟,避免启动时干扰。
- 每轮调用
check判断卡顿类型。 - 根据检测结果决定是否采样调用栈和生成报告。
- 通过代理回调通知外部监控状态和报告文件路径。
- 线程安全管理调用栈数据和状态。
卡顿检测逻辑
- 判断 RunLoop 是否超时(当前时间 - 最近一次 RunLoop 活动时间 > 阈值)。
- 判断应用是否处于后台,区别不同卡顿类型。
- 判断 CPU 使用率是否超过阈值,结合耗电堆栈采集器状态决定是否生成 CPU 卡顿报告。
- 打印 CPU 和内存使用情况,超过阈值触发回调。
- 敏感模式下额外检测 RunLoop 挂起时长。
调用栈采样
- 根据配置的采样间隔,周期性采样主线程调用栈。
- 采样时调用
WCGetMainThreadUtil获取当前调用栈,存入WCMainThreadHandler管理的循环队列。 - 采样次数和间隔根据卡顿阈值动态调整。
卡顿事件过滤
- 通过比较当前调用栈与上一次调用栈,判断是否重复。
- 采用退火算法动态调整检测间隔,避免重复上报。
- 通过
WCFilterStackHandler控制每日上报次数,防止过度报警。 - 过滤无效(调用栈长度过短)和重复卡顿事件。
卡顿报告生成
- 通过
WCDumpInterface生成卡顿报告文件,支持挂起所有线程确保快照一致。 - 支持启动阶段卡顿特殊处理,保存启动卡顿记录。
- 支持异步写文件和自定义路径。
- 生成报告时通过代理回调通知外部。
后台与前台状态处理
- 监听 UIApplication 生命周期通知,更新当前应用状态。
- 后台启动时清理历史卡顿文件,避免误报。
- 前台激活时重置启动标志,允许正常检测。
- 支持后台启动和挂起事件的特殊处理。
CPU 和内存使用监控
- 周期性采集应用和设备 CPU 使用率。
- 通过
WCCPUHandler统计 CPU 平均值,判断是否过高。 - 采集内存占用,超过阈值触发回调。
- 支持打印设备热状态(iOS 11+)。
- 支持耗电堆栈采集,分析高耗电代码路径。
热状态监听
- iOS 11+ 监听
NSProcessInfoThermalStateDidChangeNotification。 - 设备热状态升高时回调代理,方便开发者优化性能。
动态阈值调整
- 支持动态调整 RunLoop 卡顿阈值,范围限制在 400ms 到 2s。
- 阈值调整后更新检测周期和采样次数。
- 支持降低阈值以提高检测灵敏度,或恢复默认阈值。
耗电堆栈采集委托
- 实现
WCPowerConsumeStackCollectorDelegate,异步保存耗电堆栈报告。 - 生成 JSON 格式报告,保存到指定路径。
代理回调接口说明
@protocol WCBlockMonitorDelegate <NSObject>
@required
- (void)onBlockMonitor:(WCBlockMonitorMgr *)bmMgr enterNextCheckWithDumpType:(EDumpType)dumpType;
- (void)onBlockMonitor:(WCBlockMonitorMgr *)bmMgr beginDump:(EDumpType)dumpType blockTime:(uint64_t)blockTime runloopThreshold:(useconds_t)runloopThreshold;
- (void)onBlockMonitor:(WCBlockMonitorMgr *)bmMgr dumpType:(EDumpType)dumpType filter:(EFilterType)filterType;
- (void)onBlockMonitor:(WCBlockMonitorMgr *)bmMgr getDumpFile:(NSString *)dumpFile withDumpType:(EDumpType)dumpType;
- (NSDictionary *)onBlockMonitor:(WCBlockMonitorMgr *)bmMgr getCustomUserInfoForDumpType:(EDumpType)dumpType;
- (void)onBlockMonitorCurrentCPUTooHigh:(WCBlockMonitorMgr *)bmMgr;
- (void)onBlockMonitorIntervalCPUTooHigh:(WCBlockMonitorMgr *)bmMgr;
- (void)onBlockMonitorThermalStateElevated:(WCBlockMonitorMgr *)bmMgr;
- (void)onBlockMonitorMainThreadBlock:(WCBlockMonitorMgr *)bmMgr;
- (void)onBlockMonitorMemoryExcessive:(WCBlockMonitorMgr *)bmMgr;
- (void)onBlockMonitor:(WCBlockMonitorMgr *)bmMgr runloopHangDetected:(uint64_t)duration;
@end
- 通过这些方法,外部可以获得卡顿检测状态、报告生成通知、CPU 和内存异常警告、设备热状态变化等信息。
- 方便业务侧根据性能异常做日志上报、用户提示或自动恢复措施。
辅助工具方法
-
+ (unsigned long long)diffTime:(struct timeval *)tvStart endTime:(struct timeval *)tvEnd;
计算两个时间戳之间的微秒差值。 -
多个全局函数用于提供调用栈快照和性能分析数据给外部模块。
-
支持 macOS 平台的事件信号通知。
大致流程
总结
WCBlockMonitorMgr 是微信 Matrix 性能监控框架中极其重要的核心类,负责主线程卡顿检测和 CPU 监控。它设计了完善的监控流程和机制,具备丰富的配置选项和回调接口,支持 iOS/macOS 多平台,适用于复杂的性能监控场景。通过合理的采样、过滤和报告机制,能够有效捕获应用运行中的卡顿和高 CPU 使用问题,为性能优化提供有力支持。
参考: