帧率抖动基础:帧率、抖动、卡顿的定义与关系
做性能优化,绕不开三个词:帧率、抖动、卡顿。很多新手容易把它们混为一谈,觉得帧率低就是卡顿,卡顿就是因为帧率低。其实不是这样。
我个人习惯先把概念拆清楚。举个例子——一个 App 跑在 60fps,按理说每帧间隔 16.67ms。但你真拿 Perfetto 抓一把 trace 看看,很少有帧能卡得那么准。多半是 14ms、17ms、20ms 来回跳。这种跳,就是抖动。而如果某一帧突然崩到 100ms,那就是卡顿。
所以想用 Perfetto 监控后台调度导致的帧率问题,先得把这几个概念的关系吃透。
帧率(FPS)——每秒显示的帧数
帧率是大部分人最先接触的指标。60fps 意味着渲染线程每秒提交 60 帧,每帧可用时间约 16.67ms。但注意,帧率只是一个平均值,它把那些忽快忽慢的帧间隔全都平均掉了。我曾经见过一个项目,FPS 测出来是 58,看上去挺稳,但实际上每 3 秒就有一个 150ms 的大掉帧——用户感知到的就是卡,但平均帧率根本没反映出来。
这就是帧率的局限:它告诉你“量”,但不告诉你“均匀度”。
| 帧率 | 每帧间隔 | 典型场景 |
|---|---|---|
| 30 fps | 33.33 ms | 低端设备、省电模式 |
| 60 fps | 16.67 ms | 主流流畅体验 |
| 90 fps | 11.11 ms | 高刷新率屏幕 |
| 120 fps | 8.33 ms | 游戏/专业应用 |
FrameTiming 切片抓每一帧的起止时间,然后算变异系数。如果变异系数超过 10%,哪怕帧率是 59,也值得深挖。抖动(Jitter)——帧间隔的偏差
抖动是个更精细的指标。它描述的是帧间隔时间偏离理想值的程度。比如理想间隔 16.67ms,实际帧间隔序列是 [16, 17, 15, 20, 16] ms,最大偏差 3.33ms,这就是抖动。
抖动有两种常见量化方式:
- 最大抖动(Peak Jitter): 最大帧间隔减去最小帧间隔。简单直观,但对单次异常敏感。
- 均方根抖动(RMS Jitter): 计算所有帧间隔与理想值差值的均方根。更能反映整体稳定性。
我在项目中遇到过一个典型案例:某款手机在抖音滑动时,帧间隔总是在 14ms 到 20ms 之间跳,幅度不大但频率很高。用户反馈“说不出的涩”,这就是典型的抖动问题,而不是卡顿。
SurfaceFlinger 的 onFrameCommitted 下,如果看到连续几个帧间隔突然翻倍,那就要用卡顿去分析了。卡顿(Stutter)——明显的拖慢
卡顿指的是某一帧或多帧的渲染时间严重超过预期,导致用户明显感知到画面停顿或跳帧。通常,超过下一帧的 vsync 边界就算一次小卡顿,超过两三个 vsync 就算明显卡顿。
不同系统对卡顿的判定标准不同:
- Android 官方用「掉帧数」衡量(比如超过 16.67ms 的部分累计为掉帧)。
- iOS 用「帧间隔超过 32ms 的次数」来统计。
- Perfetto 里可以看
FrameTimeline里的expectedVsync和actualVsync的差值,差值越大卡顿越严重。
我曾优化过一个后台调度导致的卡顿:某个线程被调度到小核上,而且时不时被其它进程抢占,导致它处理完一帧需要 40~60ms。每次抢占了主线程的时间,屏幕就冻一下。这种卡顿从帧率上看只掉到 45fps,但用户的感知是“一顿一顿的”。
三者的关系:一图说清
下面这张图概括了帧率、抖动、卡顿的关系。你可以把它当作一个判断框架:
量化指标实战:用 Perfetto 抓住抖动
在 Perfetto 里,我们可以用几个关键切片来量化:
- FrameTimeline: 展示每一帧的预期时间与结束时间,直接看差值。
- SurfaceFlinger::onFrameCommitted: 记录每一帧提交的时间点,可以用来算帧间隔。
- Choreographer: 在 Android 上可以抓 Choreographer.doFrame 看每一帧的绘制耗时。
// 在 Perfetto SQL 里计算帧间隔抖动
SELECT
ts - lag(ts) OVER (ORDER BY ts) AS frame_duration_ns
FROM
slice
WHERE
name = 'onFrameCommitted'
ORDER BY ts
// 然后看标准差和最大值
我建议你抓一次 trace 后,直接拉出 FrameTimeline 的视图——它会用不同颜色标出哪一帧超时了。黄色是轻微超时,红色是严重超时。一眼就能看出抖动模式和卡顿分布。
常见误区避坑
总结三句话:
- 帧率是整体平均数,评估性能天花板。
- 抖动是细节偏差,决定流畅细腻度。
- 卡顿是极端异常,破坏交互连贯性。
下节课我们会具体用 Perfetto 抓一次 trace,看看后台调度怎么导致帧率抖动。这里先打好概念基础——工具是手段,理解定义和关系才是分析的起点。