概述
该机制主要基于两个核心模块:
- MatrixAppRebootAnalyzer:用于检测应用的重启类型,包括是否因OOM导致的重启。
- WCMemoryStatPlugin:用于内存分配的实时监控和内存使用情况的记录,辅助判断OOM发生。
通过这两个模块的协作,能够在应用异常退出(尤其是OOM)后,收集相关信息,进行上报和分析。
一、OOM监控关键点
1. MatrixAppRebootAnalyzer
-
功能:
- 监听应用生命周期通知(进入后台、进入前台、退出等)
- 记录应用状态(是否崩溃、是否被用户退出、是否被系统杀死等)
- 判断重启类型,如正常崩溃、用户主动退出、系统OOM杀死等
- 保存和读取历史状态数据(
MatrixAppRebootInfo
)
-
关键逻辑:
- 检测是否被调试:调试时不进行OOM检测,避免误判。
- 监听生命周期通知 :如
UIApplicationDidEnterBackgroundNotification
、UIApplicationWillTerminateNotification
等。 - 状态标记 :根据通知更新状态,如
isAppWillSuspend
、isAppSuspendKilled
等。 - 延时检测系统杀死:iOS 11.0.x 系统中,应用挂起后可能在20秒内被系统杀死,利用延时block判断是否被杀。
- 重启类型判断:根据历史状态判断是OOM导致还是其他原因。
- XPC卡顿检测:辅助检测XPC服务导致的卡顿,间接判定OOM风险。
2. WCMemoryStatPlugin
-
功能:
- 启动内存日志监控,跟踪内存分配和释放情况
- 维护内存记录(
MemoryRecordInfo
),包括OOM发生时的内存快照 - 支持手动或自动上报OOM相关数据
- 提供接口导出内存dump数据,供后续分析
-
关键逻辑:
- 启动检测 :
start
方法启动内存日志,初始化当前内存记录。 - 内存dump回调 :通过
memory_dump_callback
获取内存快照数据。 - 报告机制:根据上次重启类型(如前台OOM),自动生成并上报内存报告。
- 记录管理:支持查询、删除历史内存记录。
- 错误回调:监控过程中出现错误时,通知代理处理。
- 启动检测 :
二、监控OOM的整体流程
graph TD
A[应用启动] --> B[MatrixAppRebootAnalyzer安装监听]
B --> C[注册生命周期通知]
C --> D[应用状态变化?]
D -->|进入后台| E[notifyAppEnterBackground]
D -->|进入前台| F[notifyAppEnterForeground]
D -->|用户退出| G[notifyAppQuitByUser]
D -->|应用异常退出| H[notifyAppCrashed]
D -->|应用调用exit| I[notifyAppQuitByExit]
E --> J[更新状态isAppEnterBackground=YES]
F --> K[延时1秒后更新状态isAppEnterForeground=YES]
G --> L[更新状态isAppQuitByUser=YES]
H --> M[更新状态isAppCrashed=YES]
I --> N[更新状态isAppQuitByExit=YES]
O[应用挂起] --> P[notifyAppWillSuspend]
P --> Q[设置延时block检测是否被系统杀死]
Q -->|20秒后未取消| R[标记isAppSuspendKilled=YES]
S[应用启动时调用checkRebootType] --> T{根据状态判断重启类型}
T -->|OOM相关| U[MatrixAppRebootTypeAppForegroundOOM 或 AppSuspendOOM]
T -->|其他| V[其他重启类型]
W[WCMemoryStatPlugin启动] --> X[开启内存日志记录]
X --> Y[生成内存记录MemoryRecordInfo]
Y --> Z[内存分配监控与dump]
Z --> AA[OOM发生时生成报告并上报]
U --> AA
三、关键代码片段解读
1. 延时检测系统杀死(应用挂起时)
ini
+ (void)notifyAppWillSuspend {
// 取消前台延时block,避免误判
if (s_foregroundDelayBlock) {
dispatch_block_cancel(s_foregroundDelayBlock);
s_foregroundDelayBlock = nil;
}
// 设置一个18秒的延时block,超过则认为被系统杀死
NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
s_suspendDelayBlock = dispatch_block_create(DISPATCH_BLOCK_NO_QOS_CLASS, ^{
if ([[NSDate date] timeIntervalSince1970] - now < 20) {
s_isSuspendKilled = YES;
MatrixAppRebootInfo *info = [MatrixAppRebootInfo sharedInstance];
info.isAppSuspendKilled = YES;
[info saveInfo];
MatrixInfo(@"maybe killed after several seconds...");
}
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(18 * NSEC_PER_SEC)), dispatch_get_main_queue(), s_suspendDelayBlock);
}
2. 启动内存监控
ini
- (BOOL)start {
if ([MatrixDeviceInfo isBeingDebugged]) {
MatrixDebug(@"app is being debugged, cannot start memstat");
return NO;
}
if (m_currRecord != nil) {
return NO;
}
if ([super start] == NO) {
return NO;
}
// 初始化配置,创建内存记录
m_currRecord = [[MemoryRecordInfo alloc] init];
m_currRecord.launchTime = [MatrixAppRebootAnalyzer appLaunchTime];
m_currRecord.systemVersion = [MatrixDeviceInfo systemVersion];
m_currRecord.appUUID = @(app_uuid());
// 启用内存日志
int ret = enable_memory_logging(rootPath.UTF8String, dataPath.UTF8String);
if (ret == MS_ERRC_SUCCESS) {
[m_recordManager insertNewRecord:m_currRecord];
return YES;
} else {
disable_memory_logging();
[self.delegate onMemoryStatPlugin:self hasError:ret];
m_currRecord = nil;
return NO;
}
}
3. 生成并上报OOM报告
ini
- (void)deplayTryReportOOMInfo {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if ([MatrixAppRebootAnalyzer lastRebootType] == MatrixAppRebootTypeAppForegroundOOM) {
MemoryRecordInfo *lastInfo = [self recordOfLastRun];
if (lastInfo != nil) {
NSData *reportData = [lastInfo generateReportDataWithCustomInfo:customInfo];
if (reportData != nil) {
MatrixIssue *issue = [[MatrixIssue alloc] init];
issue.issueTag = [WCMemoryStatPlugin getTag];
issue.issueID = [lastInfo recordID];
issue.dataType = EMatrixIssueDataType_Data;
issue.issueData = reportData;
[self reportIssue:issue];
}
}
}
});
}
四、总结
- 重启原因判断:通过监听应用生命周期事件和保存状态信息,判断应用是否因OOM导致异常退出。
- 延时检测机制:利用延时block判断挂起后是否被系统杀死,捕获系统OOM杀死场景。
- 内存日志监控:启动内存日志,记录内存分配情况,生成OOM发生时的内存快照。
- 自动上报:OOM发生后,自动生成报告并上报,方便后续分析和定位问题。
- 防调试干扰:调试状态下关闭监控,避免误判。
这样设计的OOM监控机制,能够较全面地捕获OOM相关信息,辅助开发者进行问题定位和优化。