Skip to content

APM 线上性能监控与稳定性体系建设 ​

回到总览:性能、测试、排障
相关模块:Android ANR 触发机制、排障定位与防范 · Android / Java 内存泄漏定位、LeakCanary 原理与 Profiler 实战

一句话定义 ​

APM(Application Performance Monitoring,应用性能监控)是指在应用 Release 线上环境,通过轻量级无侵入的 SDK 实时采集 Crash、ANR、内存、网络、卡顿与流量等多维度性能指标,经聚合上报与告警系统实现问题精准归因的稳定性防护体系。

代码索引 ​

计划补齐的实验:

  • labs/android/host/topics/performance/apm-monitoring-demo/ — 全局 UncaughtExceptionHandler 捕获、AnrObserver 监听与打点聚合上报

为什么需要 ​

  • 为什么线下测试完全没问题的 App,上线后在用户的某些低端机型上仍会大量抛出 UncaughtException 和 ANR?
    • 一句话答:线下测试环境有限,无法覆盖生产环境中复杂的 Android 厂商定制 ROM、极端低端硬件配置、弱网环境以及用户千奇百怪的操作路径;必须依赖线上 APM 的真实用户监测(RUM)进行兜底分析。
  • 为什么 10 年 Android 工程师建设 APM 时必须遵守“极低侵入与低资源消耗”原则?
    • 一句话答:APM SDK 运行在用户真实设备上,如果监控 SDK 本身引发了频繁的内存分配、CPU 抢占或过多耗电,就会喧宾夺主导致业务性能劣化。

底层机制 ​

1. APM 监控四大核心指标与捕获机制 ​

text
                               ┌── Java Crash: Thread.setDefaultUncaughtExceptionHandler()
                               ├── Native Crash: Breakpad / Signal Catcher (SIGSEGV/SIGBUS)
     ┌── 1. 崩溃稳定性 (Crash) ┤
     │                         └── ANR: Signal 3 (SIGQUIT) / DropBox / AnrObserver
     │
     ├── 2. 性能体验 (Performance) ── JankStats 丢帧率 / 启动 TTID / 内存堆 Peak
APM ─┤
     ├── 3. 网络与 API (Network) ── OkHttp Interceptor / 慢请求率 / 错误码分布
     │
     └── 4. 资源与大图 (Resource) ── Native 内存用尽 / Bitmap 尺寸溢出监控

各指标捕获技术路线: ​

  1. Java Crash 捕获: 通过 Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) 拦截未捕获异常,记录堆栈后交给系统原生的 Handler。
  2. Native Crash (C/C++) 捕获: 注册 Linux 信号处理函数 sigaction(),捕获 SIGSEGV(段错误)、SIGABRT(放弃信号)、SIGBUS(总线错误)等信号,通过 Breakpad 提取 minidump。
  3. 网络性能监控: 通过注入 OkHttp EventListener / Interceptor 采集 DNS 解析耗时、TCP 握手耗时、SSL 握手耗时与响应 Body 尺寸。

Android / Flutter / Web / Backend 对照 ​

监控维度Android 原生Flutter 框架Web / Backend
Crash 捕获UncaughtExceptionHandler / BreakpadFlutterError.onError / PlatformDispatcher.onErrorwindow.onerror / Sentry Node SDK
APM 平台腾讯 Matrix / 字节 APM / FirebaseSentry Flutter / DatadogWeb Vitals / Prometheus + Grafana
网络插桩Bytecode Instrumentation (ASM)Custom HttpClientAdapterService Worker / Fetch API Interceptor

常见场景 ​

1. 自定义未捕获异常兜底打点 (UncaughtExceptionHandler) ​

java
public class ApmCrashHandler implements Thread.UncaughtExceptionHandler {
    private final Thread.UncaughtExceptionHandler mDefaultHandler;

    public ApmCrashHandler() {
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
    }

    public void init() {
        Thread.setDefaultUncaughtExceptionHandler(this);
    }

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        // 1. 采集上下文数据 (用户 ID、当前页面、内存剩余)
        JSONObject crashData = collectCrashInfo(t, e);
        // 2. 写入本地磁盘崩溃日志 (同步 Flush 写入)
        saveToDiskSync(crashData);
        // 3. 交还给系统原本的 Handler 展示崩溃弹框/退出
        if (mDefaultHandler != null) {
            mDefaultHandler.uncaughtException(t, e);
        }
    }
}

常见误配、事故后果与排障 ​

1. 事故:APM 日志实时同步网络上报造成死锁与二次 Crash ​

  • 误配原因:在 uncaughtException() 内部使用 OkHttp 或主线程发同步网络请求上报 Crash 数据。
  • 后果:崩溃发生时线程可能处于不稳定状态或发生了 OOM,在 Crash Handler 中发网络请求会导致二次崩溃,导致最原始的 Crash 堆栈丢失。
  • 排障与修法:崩溃触发时只做同步磁盘写入(使用 mmap / mmkv 保障写入),将网络上报逻辑留到 App 下一次冷启动时在后台线程异步补发。

与相近概念对比 ​

监控机制触发时机性能损耗典型方案
被动指标捕获 (Crash/ANR)异常事件发生时近乎 0UncaughtExceptionHandler
主动轮询监控 (Memory/FPS)定时器周期触发 (如 1s)低FrameMetrics / 线程池轮询
字节码插桩 (ASM/AspectJ)编译期插入 Trace 点中/低字节 Matrix / 听云 / NewRelic

对应实验 ​

计划补齐的实验:

  • labs/android/host/topics/performance/apm-monitoring-demo/ — 全局 UncaughtExceptionHandler 捕获、AnrObserver 监听与打点聚合上报

复习检查题 ​

  1. 在崩溃监控中,为什么 Crash 日志绝对不能在 uncaughtException 回调里直接发网络请求上报?

    答:当发生 UncaughtException 时,应用线程处于不稳定的崩溃临界状态(甚至可能是发生了内存溢出 OOM 或主线程死锁)。在回调中发起网络请求需要申请新的内存、创建 Socket 和线程,极易引发二次崩溃,导致原始的 Crash 堆栈丢失。正确的做法是仅同步写入磁盘(或 mmap 文件),待应用下一次启动时再异步上报。

  2. 针对 C/C++ 层的 Native Crash(如段错误 SIGSEGV),Java 层的 UncaughtExceptionHandler 能捕获到吗?

    答:捕获不到。Native Crash 发生在 C/C++ 层,由 Linux 内核直接向进程发送信号(Signal)。Java 层的异常处理机制只作用于 JVM/ART 抛出的 Java 异常。捕获 Native Crash 必须在 C/C++ 层通过 sigaction() 注册信号处理函数,或使用 Google Breakpad 提取 minidump 堆栈。

速记 ​

  • 崩溃防丢失:Java 抓 UncaughtException,Native 抓 SIGSEGV 信号,日志先落盘下回报。
  • APM 规则:极低侵入与性能损耗,严禁监控 SDK 本身引发卡顿与二次 OOM。

站点构建时间:2026/8/24 23:43:17