卡顿量化指标:帧率、帧时间、丢帧率、Jank 数
卡顿不是感觉,而是可以被量化的数字。把模糊的「卡」翻译成四个精确的度量:帧率、帧时间、丢帧率、Jank 数,才能判断严重程度、定位瓶颈、验证修复效果。本章建立指标的标准化定义与采集方法,作为后续排查的基础语言。
本章价值:掌握四个指标的数学含义、物理意义及 Android 平台采集手段,避免用“看起来卡”这种无效描述汇报问题。
故障树:从卡顿现象到量化指标
用户感觉“卡”时,底层是一连串渲染事件的因果链。下图为故障树的简化版,展示现象如何分解到四个指标。
指标定义与权衡
| 指标 | 数学定义 | 理想值 | 波动含义 |
|---|---|---|---|
| 帧率 (FPS) | 1 秒内实际渲染的帧总数 | ≥60 FPS(120 Hz 屏 ≥120) | 低于目标值 → 整体性能不足 |
| 帧时间 | 每帧从开始绘制到送显的耗时 (ms) | ≤16.67ms(90Hz 为 11.11ms) | 均值低但存在尖峰 → 偶发卡顿 |
| 丢帧率 | 帧时间 > 目标帧间隔的帧数 / 总帧数 ×100% | <5% | 越高表示性能不足或负载不均 |
| Jank 数 | 帧时间 ≥ 目标帧间隔 × 2 的帧数(Android 官方定义) | 尽量为 0 | 每出现一次 = 用户能感知的卡顿 |
常见误解: FPS 60 不等于不卡。若帧时间呈“跳绳”状——前一帧 10ms,下一帧 60ms,后一帧 5ms——FPS 仍可能接近 60,但用户感觉明显顿挫。此时必须看帧时间分布和 Jank 数。
数据采集方式
Android 平台提供了至少三种方式获取上述指标,按精度和实时性排序如下。
- FrameTimingMetrics(Android 12+):最精准、低开销,每个帧时间都会被记录,并可导出单帧详细阶段(测量/布局/绘制)。
- Macrobenchmark + BaselineProfile:自动化测试场景,返回 FPS、丢帧率、Jank 数,适合 CI 流水线。
- dumpsys gfxinfo / profcollect:命令行工具,适合线下分析和历史对比。
以下为通过 FrameTimingMetrics 获取帧时间的核心代码片段:
// 在 Compose Activity 或 Fragment 中注册
val frameTimingMetrics = FrameTimingMetrics.create()
frameTimingMetrics?.let { metrics ->
// 在渲染线程回调中获取最近帧的时间
val frameTimeNanos = metrics.getFrameTimeFrameMetrics()
// 转换为毫秒
val frameTimeMs = frameTimeNanos / 1_000_000f
Log.d("FrameTiming", "帧时间: $frameTimeMs ms")
// 可以用数组记录 N 帧后计算丢帧率
}
// 注意:FrameTimingMetrics 在 API 33+ 中稳定
采集建议:
- 线上监控:使用 FrameTimingMetrics 或集成第三方 APM(如 Firebase Performance),对 Jank 数设置阈值告警(例如单屏 Jank > 3)。
- 线下测试:运行 Macrobenchmark 时附加
--iterations 10并输出 50 分位 / 95 分位帧时间。 - 单帧定位:通过 Perfetto 抓取
Choreographer#doFrame和RenderThread的 trace,找到特定帧的超时原因。
排查表:根据指标数值快速定位
以下排查表帮助你在拿到数据后立马判断下一步方向。
| 现象特征 | 帧率 | 帧时间 (P50 / P95) | 丢帧率 | Jank 数 | 典型原因 |
|---|---|---|---|---|---|
| 整体慢、操作跟手但延迟 | ↓(30~40) | P50≈25ms,P95≈35ms | 30%~50% | 每帧 Jank 略多 | 布局复杂度高 / 过度绘制 |
| 忽快忽慢,动画跳跃 | 50~60 但波动 | P50=12ms,P95=50ms | 10%~20% | 少量高尖峰 | 主线程 GC / 网络回包 |
| 首次打开卡几秒 | 短暂跌到 5 | 单帧 200ms+ | 短期 90%+ | 1~2 个大 Jank | 冷启动 / 资源加载 |
| 滚动列表时间歇顿挫 | 45~55 | P50=15ms,P95=67ms | 5%~15% | 滚动过程中每屏 2~5 个 Jank | Item 复用 / 图片解码 |
预防:建立量化门禁
在开发阶段就应使用以下规则拦截卡顿合入主分支:
- 门禁规则 1:Macrobenchmark 场景下 Jank 数 ≤ 1,丢帧率 ≤ 3%。
- 门禁规则 2:单次操作帧时间 P99 不超过目标帧间隔的 1.5 倍(90Hz 下 ≤16.67ms)。
- 门禁规则 3:对比基线,帧时间均值增幅不超过 5%。
采集工具集成到 CI 后,每次 MR 自动跑一遍,卡顿风险立即可见。