UPL2-2——CPU Usage 模块

CPU Usage 模块

CPU Usage(使用率)是 Unity Profiler 中最重要的性能分析模块之一,用于展示 每一帧 CPU 所花费的时间,按类别详细划分不同系统的消耗情况,帮助开发者诊断性能瓶颈

游戏开发中会造成CPU开销的主要有:

  1. 脚本逻辑(我们编写的 C# 代码逻辑)
  2. 物理系统(Unity 内置的物理引擎 )
  3. 动画计算(Unity 中的动画状态机、骨骼动画相关的混合采样计算等等)
  4. 渲染准备(计算物体是否可见、是否剔除、构建绘制命令,渲染命令提交工作等)
  5. 资源管理和加载(加载 AssetBundle、场景、纹理、网格、材质等元数据 等)
  6. GC(垃圾回收)
  7. UI系统(GUI、UGUI 中 UI 布局计算、事件派发、渲染数据的准备等)
  8. 导航与寻路
  9. 音频处理
  10. 输入检测
  11. 网络通讯
  12. 屏幕后处理 C# 部分

等等

一般项目出现卡顿、掉帧问题可以着重排查此处

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

image

  • CPU 使用率 分析窗口 在这里通过不同模块不同颜色表达,我们可以直观的看到每一个模块对 CPU 的使用情况

    我们主要关注那些可能会影响到玩家体验的运行的耗时高峰

    image

    • Rendering:花费多少时间准备渲染命令,如Camera.Render、DrawCalls 生成阶段
    • Scripts:花费多少时间执行 C# 脚本(如 Update、Start、协程)
    • Physics:花费多少时间进行物理计算,包括碰撞检测、刚体模拟(2D/3D)
    • Animation:花费多少时间处理动画相关,比如带有蒙皮网格渲染器(Skinned Mesh Renderers)、Animation、Animator 等等和动画相关的组件
    • GarbageCollector:花费多少时间处理GC(垃圾回收),即GC 垃圾回收造成的性能抖动
    • VSync:花费多少时间等待垂直同步完成(可能会造成卡帧)
    • Global ILLumination:花费多少时间来处理实时全局光照
    • UI:花费多少时间来处理UI相关,比如 Canvas 更新、重建、批处理等 UI 绘制任务
    • Others:花费多少时间来处理不属于上述模块的其他任务,比如 Unity 编辑器本身的消耗或未分类的任务或引擎底层消耗
    • 其中的竖线中的数值 用不同颜色表示各部分耗时
    • 其中的横线:66ms(15FPS)、33ms(30FPS)、16ms(60FPS) 用于帮助你直观的看到当前帧消耗是否超过了目标帧率允许的上限
  • 模块详细信息面板显示模式(窗口下方的显示模式)

    详细信息面板包括四种显示模式:

    image

    • TimeLine(时间线视图): 显示特定帧的时间细分信息,以及该帧长度的时间轴,可以显示所有线程的性能分析数据

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

      image

    • Hierarchy(层级视图): 按时间数据的内部层级结构对执行耗时数据分组

      注意:Hierarchy 只能在视图中显示一个线程的性能分析数据,需要我们手动切换线程

      image

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

      image

    • Inverted Hierarchy(倒置层级视图): 按分析器标记对样本进行分组,并用倒置的样本堆栈显示它们

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

      image

    • Raw Hierarchy(原始层级): 以类似于发生计时的调用栈的层级结构显示时间数据

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

      image

  • Hierarchy(层级视图)相关关键信息

    image

    • 模块详细信息面板选项

      • Live:开启后可在模块详细信息面板中显示有关当前帧或选定帧的信息,关闭后,只有选择一帧时才会显示

      • Main Thread:主线程,可以在此处切换检测的线程

      • 函数调用详细信息相关选项

        • No Details:无详细信息

          不显示任何额外信息,仅显示左侧的函数调用树及其时间、GC、调用次数等

        • Related Data:相关数据

          显示与当前选中函数相关的上下文信息:

          image

          • 内联事件(Markers)
          • 线程关联
          • 调用位置的上下文

          这个对分析线程间协作和事件调度有帮助,但使用较少

        • Calls:调用信息

          “调用”视图显示了所选示例的调用来源以及它调用的其他函数。
          用于分析该函数是在哪个逻辑路径下被调用的,可以帮助你定位谁在调用它,尤其在频繁调用的函数追溯调用源时很实用

          image

        使用建议:

        1. 只关心函数耗时,使用 No Details 即可
        2. 想找出某函数是被谁调用,使用 Calls
        3. 想看函数在不同线程或上下文的分布,使用 Related Data
    • 执行逻辑耗时表头

      • Total:占该帧总时间的百分比 表示当前函数(含其所有子函数)总耗时占该帧总耗时的百分比。 通常用来判断“这一支调用链是否值得深挖”

      • Self:占该帧总时间的百分比,不包含Unity调用子函数所花费的时间

        比如:某个函数花费大量时间去执行。但是因为它调用了大量的系统的 绘制 和 剔除 函数。
        但是,当您排除它调用的函数的样本时,只有 0.2% 的时间花在该函数本身上 可用于判断函数本身是否耗时大

      • Calls:在此帧中该函数的调用次数 高调用频率可能是性能瓶颈的来源

      • GC Alloc:此函数在该帧中触发的 GC 内存分配量(单位:Byte),过高可能导致频繁 GC

      • Time ms:当前函数(含子函数)在该帧的总耗时,单位是毫秒。

      • Self ms:在该帧中自身花费的总时间,不包含Unity调用子函数所花费的时间

    • Main Thread 两大循环

      • EditorLoop:Unity 编辑器运行时的主循环(非 Play 模式下),编辑器中的各面板更新,UI重绘,资源导入,编译,插件逻辑等等都会在该循环中执行
      • PlayerLoop:游戏运行时的主循环,几乎所有的游戏逻辑、渲染、物理、输入、协程、动画等等都在这个循环中执行,展开后,就是在该次循环中执行的函数相关信息

    观察建议:

    1. 总耗时高但 Self ms 低;说明慢在子函数里,应该点开看下层函数
    2. Self ms 高;当前函数本身有问题,如密集计算或阻塞
    3. Calls 很高;是否有不必要的循环调用?应考虑合并或缓存
    4. GC Alloc 明显;是否频繁 new 对象或字符串拼接?可能造成 GC
  • TimeLine(时间轴视图)相关关键信息

    image

    • Thread 常用线程显示

      • Main Thread:主线程,运行大部分游戏逻辑,包括脚本、物理、渲染提交等
      • Render Thread:渲染线程,负责将渲染命令提交给 GPU(通常异步进行)
      • Job:Unity Job System 调度的多线程任务(用于并行计算)
      • Loading:资源加载线程,例如异步读取纹理、场景、AssetBundle 等
      • Scripting Threads:非主线程的 C# 脚本线程(例如自定义后台线程) 等等
    • Live:开启后可在模块详细信息面板中显示有关当前帧或选定帧的信息,关闭后,只有选择一帧时才会显示

    • 彩色横条块

      1. 每个条代表一个采样事件(采样函数/操作)

      2. 宽度表示执行耗时,颜色表示模块类别(Scripts、Rendering 等)

      3. 点击时显示名称和耗时,如 Profiler.FlushCounters (0.046ms),可以复制或者跳转到对应 Hierarchy 视图

        image

    • 右上角其他选项

      image

      • Show Full Scripting Method Names:显示完整的脚本方法名称,包括其命名空间

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

        image

    使用建议:

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

CPU Usage 对于我们的意义

  1. 找 CPU 性能瓶颈

    查看每帧中哪个模块耗时异常(TimeLine 颜色块明显突起),快速定位卡顿来源,哪帧卡了、哪个模块卡了

  2. 找性能抖动

    检查 GC 是否频繁(黄色峰值),还是某个帧的脚本逻辑执行消耗过大(蓝色占比高)

  3. 找优化依据

    明确是脚本、渲染、物理还是 VSync(垂直同步)等模块引起的卡顿

  4. 帧率诊断

    对比 16ms(60FPS)/ 33ms(30FPS) 标尺,判断是否达标

垂直同步

显示器通常以固定的频率刷新画面(如 60Hz 表示每秒刷新 60 次,每帧 16.67ms),而显卡渲染图像的速度通常不固定,有时快于显示器刷新,有时慢于显示器刷新
这种差异,尤其是高帧率情况下可能导致画面出现撕裂异常,而垂直同步可以通过限制显卡来避免这种情况

关于垂直同步带来的问题,详细可见:UPL4-4——垂直同步带来的等待问题

垂直同步(VSync)会强制显卡:

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

影响帧率主要有两种情况:

  1. 帧率略高于刷新率 → 强制等待

    比如显卡渲染能力是 90FPS,而显示器是 60Hz;VSync 开启后,GPU 只能 每 16.67ms 渲一帧 → 被“卡”在 60FPS

  2. 帧率低于刷新率 → 被“降档”处理

    比如显卡当前只能 50FPS,VSync 要求必须整除刷新频率,于是 GPU 被 “降档” 到 30FPS(60Hz ÷ 2),这会造成严重卡顿或掉帧感

垂直同步何时开关

  • 开发调试时:通常关闭 VSync 观察真实的 GPU 性能瓶颈
  • 低端机运行卡顿时:关闭 VSync 可减少帧率锁死卡顿
  • 正式发包时:一般开启 VSync 防止撕裂(尤其是主机或高帧率设备),或者交给玩家在设置中进行设置

Unity 的垂直同步如何设置

  1. Unity 的垂直同步设置 API 为: QualitySettings.vSyncCount,其中,设置不同值代表:

    1
    QualitySettings.vSyncCount = 0;
    • 0 : 关闭垂直同步
    • 1 : 每帧同步
    • 2 : 隔一帧同步
  2. 编辑器中设置

    Edit > Project Settings > Quality

    image

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