帧率抖动定义与影响

都说掉帧,但帧率抖动到底是个什么东西?我见过不少团队把偶尔一次卡顿叫抖动,又把持续低帧也叫抖动,其实这两码事。说白了,帧率抖动是指帧率在时间轴上的不规则波动——不是帧率低,而是帧率忽高忽低。

1. 到底什么是帧率抖动?

拿一个实际场景举例:你的应用跑在 60fps,理想情况下每帧耗时 16.6ms。突然有一帧花了 80ms,然后下一帧又回到 16ms,接着再来一帧 50ms……这种非周期性的延迟变化,就是抖动。

你想想看,它跟「帧率低」有本质区别:

  • 帧率低(比如稳定 30fps):每一帧都花 33ms,画面节奏均匀,用户适应后其实不太难受。
  • 帧率抖动(比如 60fps 里突然冒出两个 80ms 的帧):画面突然顿一下,节奏被打断,用户立刻觉得“卡”。

我在项目中遇到过这种情况:用 dumpsys gfxinfo 看平均帧率 55fps 很漂亮,但用 Systrace 一看,后台调度每隔 1~2 秒就触发一次高频唤醒,把渲染线程抢走了。那几帧的耗时直接飙到 90ms 以上——这就是典型的后台调度造成的帧率抖动。

2. 度量指标之一:Jank(卡顿计数)

怎么量化抖动?最直观的指标就是 Jank。它统计的是「超时帧」的数量。

怎么算?我们定一个阈值(通常取目标帧率的 2 倍耗时)。比如目标是 60fps,阈值就是 33ms(2 帧的耗时)。任何一帧耗时超过 33ms,就算一次 Jank。

目标帧率 Jank 阈值 含义
30fps 66ms 超过 2 帧未更新的帧
60fps 33ms 超过 2 帧未更新的帧
120fps 16.6ms 超过 2 帧未更新的帧

Jank 的优点是直观:你看到数字就能知道「这轮测试里一共卡了多少次」。但它有个致命缺陷——它只看单帧是否超标,不看超标幅度。

// 伪代码示意:Jank 计数逻辑
int jankCount = 0;
for (long frameTime : frameTimes) {
    if (frameTime > JANK_THRESHOLD_MS) {
        jankCount++;
    }
}
// 输出:Jank = 23 次,但不知道每帧到底卡了多少毫秒

我曾经犯过一个错:只看 Jank 数量就觉得性能好。结果用户反馈“一卡一卡的”,最后发现虽然 Jank 数不多(才 3 次),但每次卡顿都长达 150ms——用户体验极差。所以 Jank 只能当敲门砖,不能做唯一判断。

3. 度量指标之二:FrameTime 方差

要弥补 Jank 的不足,我们必须看帧耗时的离散程度。说白了,就是这些帧的耗时到底有多散?标准差或方差是最合适的工具。

方差越大,帧之间的间隔越不均匀,抖动越严重。极端情况:假设所有帧都是 16.6ms,方差为 0,完美平滑。但如果有一半帧是 8ms,另一半是 25ms,方差就很大,虽然平均帧率可能依然是 60fps,但画面会明显一快一慢。

计算公式(标准方差):

σ = sqrt( Σ (frameTime_i - mean)^2 / N )

单位:ms。值越小越好。

我们团队内部设了一个经验阈值:对于 60fps 的目标,FrameTime 方差超过 3ms,用户就能感知到不流畅;超过 6ms,卡顿就非常明显了。你有没有发现,有些手机在系统更新后会变“卡”?其实很多时候帧率没变(还是 60fps),但方差从 2ms 跳到了 8ms——这就是典型的抖动恶化。

4. 帧率抖动对用户体验的负面影响

别小看抖动,它带来的影响比稳定低帧率要严重得多。我来讲几个实际感知:

  • 视觉卡顿:人眼对节奏变化极其敏感。稳定 30fps 可以接受,但 60fps 里混进 3 帧 100ms 的延迟,大脑会立刻提示“画面断了”。
  • 触控延迟:触控采样和渲染是联动的。如果渲染抖了一下,触摸响应也会跟着滞后——你滑动一下,页面过一会才动。我做短视频播放器优化时亲测过,抖动从 5ms 涨到 15ms 方差时,用户划屏翻页的误触率直接翻倍。
  • 功耗恶化:抖动往往伴随着频率变化和线程调度扰动。后台调度一抢 CPU,渲染线程就得等,系统为了补帧会突然拉高频率,功耗曲线像过山车一样。你想想看,本来平稳的功耗,硬生生被抖出一个个尖峰,电池扛不住。
  • 系统响应变慢:Android 的输入系统与 VSYNC 挂钩。抖动会导致输入事件排队,出现“按了按钮没反应”或“动画回弹卡住”。

我记得做一个地图应用时,后台定位同步导致帧率抖动,用户反馈“放大缩小地图时画面一抽一抽的”,开 Systrace 一查发现是 GPS 唤醒触发了 Binder 同步,把主线程卡了 40ms。这 40ms 放平均值里根本看不出来,但方差直接飙到 12ms。

一句话总结: 帧率抖动 = 帧耗时标准差超标 + 用户感知卡顿 + 后台调度元凶。

下面这张图帮你把整个知识体系串起来:

帧率抖动知识体系(第2章) 📐 帧率抖动定义 帧耗时非周期性波动 📊 度量指标 Jank + FrameTime方差 🖐️ 用户体验影响 卡顿/触控延迟/功耗 稳定帧率 vs 抖动 频率不同 & 节奏不同 Jank 计数 超2帧耗时才计数 方差/标准差 离散程度量化 视觉卡顿 节奏破坏 触控延迟 反应滞后 🔑 核心要点 Jank 看数量,方差看幅度;两者结合才能准确诊断帧率抖动 🔥 常见元凶:后台调度 定位唤醒 / Binder IPC / 线程抢占

从上图可以看得很清楚:帧率抖动 ≠ 帧率低,它有自己的度量体系,而且对用户体验的伤害比单纯掉帧更隐蔽、更难受。尤其是我前面提到的后台调度场景——一个非必要的定位唤醒,可能就把整个系统节奏打乱了。下节课我们用 Systrace 把这个元凶抓出来。