5.Profiler窗口 CPU Usage

5.Unity性能分析工具-CPUUsage


5.1 知识点

CPU Usage是什么

CPU Usage(CPU 使用率)是 Unity Profiler 里最常用、也最“顶用”的模块之一。它会把每一帧 CPU 花了多少时间拆开,并按类别(脚本、物理、动画、渲染准备、GC……)统计出来,方便你快速判断瓶颈在哪里。

游戏开发里常见的 CPU 开销来源:

  1. 脚本逻辑:我们写的 C# 代码(Update、协程、各种管理器逻辑等)
  2. 物理系统:Unity 内置物理引擎(碰撞检测、刚体模拟等)
  3. 动画计算:动画状态机、骨骼动画混合采样、蒙皮等
  4. 渲染准备:剔除、排序、构建绘制命令、提交渲染命令等
  5. 资源管理与加载:加载 AssetBundle、场景、纹理、网格、材质等元数据
  6. GC(垃圾回收):托管堆回收造成的卡顿/抖动
  7. UI 系统:GUI/UGUI 的布局计算、事件派发、批处理与渲染数据准备
  8. 导航与寻路
  9. 音频处理
  10. 输入检测
  11. 网络通讯
  12. 屏幕后处理(C# 部分)
  13. ……以及一些未分类的引擎底层开销

一般项目出现卡顿、掉帧问题,第一时间都可以先从 CPU Usage 开始排查。

CPU Usage中各参数功能的含义和作用

CPU 使用率 分析窗口

这里会用不同颜色把每一帧的 CPU 时间拆开,你可以很直观地看到“到底是谁在吃时间”。常见分类含义如下:

  • 渲染准备(Rendering):准备渲染命令的时间,比如 Camera.Render、生成 DrawCalls 的阶段
  • 脚本(Scripts):执行 C# 脚本的时间(如 UpdateStart、协程等)
  • 物理(Physics):物理计算时间,包括碰撞检测、刚体模拟(2D/3D)
  • 动画(Animation):动画相关时间(Skinned Mesh RendererAnimationAnimator 等)
  • 垃圾回收(GarbageCollector):GC 产生的回收时间,常见为“抖一下/突然卡一下”
  • 垂直同步等待(VSync):等待垂直同步的时间(有时会表现成“帧被卡住”)
  • 全局光照(Global Illumination):实时全局光照相关 CPU 开销
  • UI:UI 相关(Canvas 更新、重建、批处理、渲染数据准备等)
  • 其它(Others):不属于以上分类的内容,比如编辑器自身开销、未分类任务、引擎底层消耗等

  • 竖线上的数值:当前选中帧里,各颜色块对应的耗时(单位 ms)
  • 横向参考线
    • 66ms(15FPS)
    • 33ms(30FPS)
    • 16ms(60FPS)
    • 用来快速判断:这一帧是不是已经超过目标帧率的“时间预算”

模块详细信息面板


注意:

  • TimeLine 视图可以显示所有线程的性能数据
  • Hierarchy 视图一次只显示一个线程的数据,需要手动切换线程
TimeLine(时间线视图):


显示特定帧的时间细分信息,以及该帧长度的时间轴。

  • 显示方式:横向时间轴,按线程显示每个函数的开始与持续时间,精确到每个调用片段
  • 结构:一个横轴 = 一帧时间,纵轴 = 不同线程(Main Thread、Render Thread 等)
  • 用途
    • 看每个函数调用在时间上所占的位置和长度
    • 清楚显示函数调用之间是否并发/串行
    • 非常适合排查 主线程阻塞、线程切换耗时 等问题
Hierarchy(层级视图):


按时间数据的内部层级结构对这些数据分组

  • 显示方式:以调用栈的方式展示函数调用结构,从根函数一路展开
  • 结构:每一行是一个函数调用,子函数缩进在其下方
  • 用途
    • 快速发现“树顶函数”调用最多的分支
    • 定位哪一个函数调用下挂着最多性能开销
Inverted Hierarchy(倒置层级视图):


按分析器标记对样本进行分组,并用倒置的样本堆栈显示它们。

  • 显示方式:将调用树倒过来看,从最底层函数反推“是哪些函数调用了它”
  • 用途
    • 用于分析一个具体函数被谁频繁调用
    • 常用于调试“这个慢函数为什么会被频繁触发”的问题
    • 和 Hierarchy(层级视图)是互补关系
Raw Hierarchy(原始层级):


以类似于发生计时的调用栈的层级结构显示时间数据

  • 显示方式:不做任何聚合和折叠处理,展示完整原始采样数据
  • 用途
    • 查看完整调用链
    • 更贴近采样器采集的真实结构,但可能非常冗长复杂

Hierarchy(层级视图)

常用开关与入口:

  • Live:开启后显示当前帧/选定帧的信息;关闭后只有选中某一帧时才显示
  • Main Thread:当前查看的线程(可在这里切换要分析的线程)
  • 搜索栏:按函数名搜索

关键列(读数):

  • Total:当前函数(包含子函数)占该帧总时间的百分比
    • 常用来判断:这一整条调用链值不值得继续深挖
  • Self:函数自身占用的百分比(不包含子函数耗时)
    • 例子:某函数 Total 很高,但 Self 只有 0.2%,说明真正耗时在它调用的子函数里
  • Calls:该函数在这一帧的调用次数
    • 调用次数很高时,往往要注意是不是不必要的重复调用
  • GC Alloc:该函数在这一帧触发的 GC 分配量(单位 Byte)
    • 明显偏大时,通常意味着频繁 new / 字符串拼接 / 临时容器等,后面可能引发 GC 卡顿
  • Time ms:当前函数(含子函数)在该帧的总耗时(毫秒)
  • Self ms:函数自身耗时(毫秒,不包含子函数)

两个常见“根节点”:

  • EditorLoop:编辑器主循环(非 Play 模式),面板更新、UI 重绘、资源导入、编译、插件逻辑等都会在这里发生
  • PlayerLoop:游戏运行时主循环(Play 模式),脚本、渲染、物理、输入、协程、动画等基本都挂在这条链上

观察建议:

  1. Total 高但 Self ms 低:慢在子函数,继续展开下层
  2. Self ms 高:函数本身可能有问题(密集计算/阻塞)
  3. Calls 很高:是否有不必要的循环调用?考虑合并/缓存
  4. GC Alloc 明显:是否频繁创建对象/字符串?后面容易触发 GC

额外信息下拉框


这里控制右上角的“额外信息”展示方式:

  • No Details:不显示额外信息,只看函数树 + 时间/GC/调用次数等
  • Related Data:显示与当前样本相关的上下文信息(Markers、线程关联、调用位置上下文等),用得相对少,但分析线程协作时会有帮助
  • Calls:显示该样本的调用来源与它调用的其他函数
    • 常用于追溯“这个函数到底是被谁调用出来的”

使用建议:

  1. 只关心耗时 → 用 No Details
  2. 想找调用源头 → 用 Calls
  3. 想看线程/上下文相关信息 → 用 Related Data

TimeLine(时间线视图)

  • TimeLine 会按线程把一帧里的时间切片铺开。常见线程含义:

    • Main Thread:主线程,跑大部分游戏逻辑(脚本、物理、渲染提交等)
    • Render Thread:渲染线程,把渲染命令提交给 GPU(通常异步)
    • Job:Job System 的多线程任务(并行计算)
    • Loading:资源加载相关(异步读取纹理/场景/AssetBundle 等)
    • Scripting Threads:非主线程的 C# 脚本线程(例如自定义后台线程)
    • ……等等
  • Live:开启后显示当前帧/选定帧信息;关闭后只有选中某一帧才显示

  • 彩色横条块:

    1. 每条代表一个采样事件(函数/操作)
    2. 宽度 = 耗时,颜色 = 模块类别(Scripts/Rendering 等)
    3. 悬浮可查看名称与耗时(例如 Profiler.FlushCounters (0.046ms)
  • Show Full Scripting Method Names:显示完整的脚本方法名称

  • Show Flow Events:显示线程间异步任务的调用路径(比如 Job 与 Main Thread 的联系线)

    使用建议:

    1. 多线程性能分析(例如:Job 执行耗时)
    2. 追踪跨线程任务顺序(例如:资源加载 → 渲染)
    3. 视觉化查看整帧分布结构

CPU Usage对于我们的意义

问题:看 CPU Usage 到底能帮我们解决什么问题?

  1. 找 CPU 性能瓶颈
    • 看每帧里哪个模块耗时异常(颜色块明显突起)
    • 快速定位卡顿来源:哪一帧卡了、卡在什么模块
  2. 找性能抖动
    • 检查 GC 是否频繁(黄色峰值)
    • 或者某帧脚本逻辑执行过重(蓝色占比高)
  3. 找优化依据
    • 明确是脚本、渲染、物理还是 垂直同步(VSync)等模块引起的卡顿
  4. 帧率诊断
    • 对比 16ms(60FPS)/33ms(30FPS) 标尺,判断是否达标

垂直同步为什么会影响帧率,如何设置

为何会影响

显示器通常以固定频率刷新画面(如 60Hz 表示每秒刷新 60 次,每帧约 16.67ms)。但显卡渲染速度不固定:有时快于显示器刷新,有时慢于。

垂直同步(VSync)会强制显卡“按显示器节奏交帧”:

  1. 等显示器准备好再提交新帧(等一次“垂直回扫”信号),避免屏幕撕裂
  2. 如果显卡渲染太快,它需要等一等
  3. 如果渲染太慢,可能会错过刷新窗口,导致延后一轮提交

影响帧率常见两种情况:

  1. 帧率略高于刷新率 → 强制等待
    • 例如显卡能跑 90FPS,显示器 60Hz;开启 VSync 后,GPU 每 16.67ms 才交一帧 → 体验上会被“卡”在 60FPS
  2. 帧率低于刷新率 → 被“降档”处理
    • 例如当前只能 50FPS,VSync 要求必须整除刷新频率,于是可能被“降档”到 30FPS(60Hz ÷ 2)
      这会造成明显卡顿或掉帧感
何时开关
  • 开发调试时:通常先关闭 VSync,观察更真实的性能瓶颈
  • 低端机运行卡顿时:关闭 VSync 有时能避免“锁档”带来的更强掉帧感
  • 正式发包时:一般开启 VSync 防止撕裂(或交给玩家在设置中控制)
如何设置
  1. 代码控制
QualitySettings.vSyncCount = 0;
// 0:关闭垂直同步
// 1:每帧同步
// 2:隔一帧同步
  1. 编辑器中设置

垂直同步相关:Edit > Project Settings > Quality

  • Don't Sync(0):关闭 VSync
  • Every V Blank(1):每次垂直同步(默认)
  • Every Second V Blank(2):隔一帧同步(更低帧率)

5.2 知识点代码

Lesson05_Unity性能分析工具_CPUUsage.cs

public class Lesson05_Unity性能分析工具_CPUUsage
{
    #region 知识点一 CPU Usage是什么

    /*
     * CPU Usage(CPU 使用率)
     * - Unity Profiler 中最重要的性能分析模块之一
     * - 用于展示每一帧 CPU 所花费的时间,并按类别细分不同系统的消耗情况,帮助诊断性能瓶颈
     *
     * 游戏开发中常见 CPU 开销来源:
     * 1. 脚本逻辑(我们编写的 C# 代码逻辑)
     * 2. 物理系统(Unity 内置物理引擎)
     * 3. 动画计算(状态机、骨骼动画混合采样等)
     * 4. 渲染准备(可见性/剔除/构建绘制命令/渲染命令提交等)
     * 5. 资源管理和加载(AssetBundle/场景/纹理/网格/材质等元数据)
     * 6. GC(垃圾回收)
     * 7. UI 系统(布局计算、事件派发、渲染数据准备等)
     * 8. 导航与寻路
     * 9. 音频处理
     * 10. 输入检测
     * 11. 网络通讯
     * 12. 屏幕后处理 C# 部分
     * ……等等
     *
     * 一般项目出现卡顿、掉帧问题可以着重排查此处。
     */

    #endregion

    #region 知识点二 CPU Usage中个参数功能的含义和作用

    /*
     * CPU Usage 各参数的含义与作用:
     * - 详见笔记正文(CPU Usage 分析窗口、模块详细信息面板、四种视图、字段含义等)
     */

    #endregion

    #region 知识点三 CPU Usage对于我们的意义

    /*
     * 1. 找 CPU 性能瓶颈:哪帧卡了、哪个模块卡了
     * 2. 找性能抖动:GC 是否频繁、脚本是否突然变重
     * 3. 找优化依据:脚本/渲染/物理/VSync 等哪个是主要原因
     * 4. 帧率诊断:对比 16ms(60FPS)/33ms(30FPS)等标尺,判断是否达标
     */

    #endregion

    #region 知识点四 垂直同步为什么会影响帧率,如何设置

    /*
     * 为何影响:
     * - 显示器刷新有固定节奏(例如 60Hz ≈ 16.67ms/帧),VSync 会让 GPU 按刷新节奏交帧
     * - GPU 太快会等待,GPU 太慢会错过刷新窗口,可能出现“锁档/掉帧”
     *
     * 何时开关:
     * - 开发调试通常先关,观察更真实的瓶颈
     * - 低端机卡顿时关掉可能更顺(避免锁档)
     * - 正式包常开防撕裂(或提供给玩家设置)
     *
     * 如何设置:
     * - 代码:QualitySettings.vSyncCount = 0/1/2
     * - 编辑器:Project Settings > Quality
     */

    #endregion
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏