帧率(FPS)基础:什么是帧率、帧时间、丢帧与卡顿

做性能优化这么多年,我经常看到新人一上来就问「FPS怎么提」。说实话,只盯着FPS数字看,容易走弯路。咱们先打下基础,把帧率、帧时间、丢帧、卡顿这几个概念理清楚。

帧率(FPS)—— 最熟悉的陌生人

帧率,全称 Frames Per Second,每秒能渲染多少帧。60 FPS 就是一秒60张画面。

我个人习惯把 FPS 当作一块「速度表」,但它的值其实是平均的。你想想看,游戏引擎每帧的耗时不可能完全一样,有的帧快(8ms),有的帧慢(20ms),平均下来 FPS 可能正好60。但用户感受到的流畅度,完全取决于最慢的那几帧。

我的经验: 做性能分析时,我通常会同时打开 FPS 曲线和帧时间曲线。单纯看 FPS,你会错过很多细节。记得有一次线上项目FPS稳定在59~61,但玩家疯狂骂卡顿,根源就是帧时间抖动太厉害。

帧时间(Frame Time)—— 真正的「底牌」

帧时间就是处理一帧需要的总耗时,单位通常是毫秒(ms)。

公式很简单:帧时间 = 1000 / FPS。反过来也一样:FPS = 1000 / 帧时间。

举个例子:目标60 FPS时,每帧的时间预算只有16.67ms。如果你的渲染、逻辑、物理等加起来超过了这个数,帧率就会往下掉。

目标 FPS目标帧时间(ms)我的建议
3033.33移动端低配保底
6016.67主流舒适区
9011.11高端体验线
1208.33电竞级

这里有个坑:很多人只盯着平均帧时间,忽略了**99%分位帧时间**。我在项目里常常看到平均帧时间只有10ms,但99%分位跳到30ms,那就说明每100帧里就有一帧卡成幻灯片。这种卡顿比稳定低帧更难排查。

丢帧(Frame Drop)与卡顿(Stutter)—— 一对孪生兄弟

丢帧就是某一帧因为超时而直接被跳过,或者渲染结果没有被显示。卡顿则是用户感知到的停顿、抖动。

说白了,丢帧是原因,卡顿是结果。一次丢帧可能用户察觉不到,但连续丢帧或者一帧耗时特别长,就会产生明显卡顿。

避坑指南: 我曾经接手过一个项目,FPS曲线看起来很漂亮,60帧几乎一条直线。但是玩家反馈“走路一卡一卡的”。后来我用 Profiling 工具一抓,发现每2~3秒会出现一次帧时间尖峰,高达50ms!虽然平均帧时间还在16ms左右,但尖峰导致连续丢2~3帧,直接表现为卡顿。从那以后,我把 帧时间上限 + 丢帧次数 作为核心指标。

用代码看帧时间

拿 Unity 举例,你可以这样拿到每帧的时间:

float frameTime = Time.deltaTime * 1000f; // 单位ms
float fps = 1f / Time.unscaledDeltaTime;

if (frameTime > 16.67f)
{
    Debug.LogWarning("Frame over budget! Frame time: " + frameTime);
}

Unreal 里就更直接了,控制台输入 stat unit 就能看到 Game、Render、GPU 分别的耗时。我习惯把这几行输出录到文件里,做长时间分析。

知识体系:帧率、帧时间、丢帧、卡顿的关系

下面的图可以帮你一次理清它们之间的关系。

帧率、帧时间、丢帧、卡顿核心关系 帧率 (FPS) 帧时间 (ms) 目标帧时间
(如16.67ms) 互为倒数 比较 超时检测 丢帧 卡顿 关键指标 • 平均帧时间 • 99%分位帧时间

从上到下看:帧率和帧时间互为倒数,你将实际帧时间与目标帧时间比较,一旦超时就标记丢帧,多次丢帧累积成用户感知的卡顿。明白这个链条,你就知道优化该从哪里入手了。

丢帧的两大类型

  1. 单帧尖峰 —— 某帧突然耗时极高(比如GC触发、资源加载),造成一次丢帧。这种丢帧频率不高的话影响较小。
  2. 持续高负载 —— 每一帧都超预算,帧率直接掉档(比如从60掉到30)。这种卡顿感受最明显。

我个人习惯用性能分析工具(如 Unity Profiler 或 Unreal Insights)记录每帧时间,然后看帧时间分布直方图。如果99%的帧都在16ms以下,那基本不会有卡顿。

小心掉帧陷阱: 有些引擎的 FPS 统计会跳过实际显示帧,比如垂直同步(VSync)开启时,如果渲染完成但错过了刷新窗口,那帧会被丢弃,但计数器依然算“渲染了一帧”。这种丢帧在计数器里看不出来!我建议用 显示帧率 而不是渲染帧率来做优化目标。

小结几个关键点

  • 不要只看 FPS,帧时间才是根本。
  • 丢帧是帧时间超预算的直接后果,卡顿是丢帧的宏观表现。
  • 优化目标应该是:降低平均帧时间 + 消除帧时间尖峰。
  • 用工具抓取99%分位帧时间,比看平均值更靠谱。

嗯,这章的内容就到这。你把帧率、帧时间、丢帧、卡顿的关系吃透了,后面讲跨模块通信延迟的时候,就能更准地找到真正的瓶颈。咱们下章见。