Matrix内存溢出(OOM)监控机制分析

概述

该机制主要基于两个核心模块:

  • MatrixAppRebootAnalyzer:用于检测应用的重启类型,包括是否因OOM导致的重启。
  • WCMemoryStatPlugin:用于内存分配的实时监控和内存使用情况的记录,辅助判断OOM发生。

通过这两个模块的协作,能够在应用异常退出(尤其是OOM)后,收集相关信息,进行上报和分析。


一、OOM监控关键点

1. MatrixAppRebootAnalyzer

  • 功能

    • 监听应用生命周期通知(进入后台、进入前台、退出等)
    • 记录应用状态(是否崩溃、是否被用户退出、是否被系统杀死等)
    • 判断重启类型,如正常崩溃、用户主动退出、系统OOM杀死等
    • 保存和读取历史状态数据(MatrixAppRebootInfo
  • 关键逻辑

    • 检测是否被调试:调试时不进行OOM检测,避免误判。
    • 监听生命周期通知 :如 UIApplicationDidEnterBackgroundNotificationUIApplicationWillTerminateNotification 等。
    • 状态标记 :根据通知更新状态,如 isAppWillSuspendisAppSuspendKilled 等。
    • 延时检测系统杀死: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相关信息,辅助开发者进行问题定位和优化。

相关推荐
程序视点20 小时前
2025最佳Windows优化工具推荐:292KB小工具解决Win11右键菜单/自动更新/Defender等12大痛点
windows·性能优化
林开落L1 天前
进程控制:从创建到终结的完整指南
linux·性能优化·进程控制
OEC小胖胖1 天前
性能优化(一):时间分片(Time Slicing):让你的应用在高负载下“永不卡顿”的秘密
前端·javascript·性能优化·web
CodeShare2 天前
Windows 11任务管理器CPU计算逻辑优化
性能优化·操作系统
程序员编程指南2 天前
Qt 移动应用性能优化策略
c语言·开发语言·c++·qt·性能优化
鼠鼠我捏,要死了捏2 天前
MySQL 索引设计与查询性能优化实践指南
数据库·mysql·性能优化
励志成为糕手2 天前
编程语言Java——核心技术篇(五)IO流:数据洪流中的航道设计
java·开发语言·性能优化
在未来等你2 天前
RAG实战指南 Day 28:RAG系统缓存与性能优化
性能优化·信息检索·缓存策略·llm应用·rag系统
DemonAvenger2 天前
SQL语句详解:SELECT查询的艺术 —— 从基础到实战的进阶指南
数据库·mysql·性能优化