性能优化的第一步,是确定哪一部分工作消耗了帧预算。减少某个函数的执行时间,如果这个函数并非限制帧率的因素,最终体验可能不会改变。下面的流程以 Unity 6.0 官方 Profiler 文档为参考,具体模块和标记可能随平台与版本变化。

从帧时间预算开始

60 FPS 对应每帧约 16.67 毫秒,120 FPS 对应约 8.33 毫秒。平均 FPS 容易掩盖偶发长帧,因此应同时观察帧时间分布和持续时间较长的尖峰。一次资源加载或垃圾回收造成的长帧,可能比平均帧率的小幅变化更影响手感。

CPU 与 GPU 通常是流水工作的,不能简单把两个耗时相加当成最终帧时间。垂直同步、帧率上限、平台调度与线程同步也会产生等待。先确认目标帧率和采样场景,才能判断一段等待是性能瓶颈还是正常的帧率限制。

在目标设备上采样

Editor 中的 Play Mode 适合快速定位方向,但包含编辑器、Inspector 和 Profiler 本身的开销。最终判断应结合目标平台上的构建数据,特别是移动设备的热状态、图形 API 和实际分辨率。

  1. 固定一个可复现的场景,例如同样的敌人数、相机路径和画质设置。
  2. 使用 Development Build,并按需求连接 Profiler;记录 Unity 版本、设备和渲染设置。
  3. 等待必要的资源加载和初始化完成,区分首次运行开销与稳定运行开销。
  4. 采集正常帧与问题帧,并保留样本用于前后比较。

开发构建和 Profiler 自身仍会改变性能。找到问题并修改后,还应在接近发布的构建中复核体验。Deep Profiling 会为大量方法增加采样开销,适合缩小范围后的诊断,不宜直接把其耗时当成发布环境结果。

用 Timeline 解释主线程与等待

CPU Usage 模块的 Timeline 可以同时显示多条线程在时间轴上的工作。先查看长帧内主线程、渲染线程和工作线程的关系,再使用 Hierarchy 追踪某个样本的总耗时、自身耗时和调用次数。

  • 脚本热点:查看是否存在高频调用、重复查询或某次突发处理。
  • 渲染提交:关注相机、材质切换、对象可见性与管线处理成本。
  • 线程等待:结合前后线程的工作判断等待原因,不能只看到名字就下结论。
  • GC.Alloc:它反映托管分配,不能直接等同于这一帧已发生垃圾回收。

例如某些 Present 或同步相关标记出现很长等待,可能与 GPU 负载有关,也可能来自 VSync 或帧率限制。应结合 GPU 模块、目标平台支持情况和设置变化验证,而不是一看到等待就去重写脚本。

一次只验证一个主要假设

如果怀疑物理查询次数过多,可以先减少重复查询,再在同样场景重新采样;如果怀疑填充率,则可以临时降低渲染分辨率观察变化。这样的控制变量实验比同时修改十个系统更容易解释结果。

记录修改前后的主线程、GPU、托管分配和长帧表现,并说明测试条件。某项优化也可能把 CPU 开销转移成额外内存,或在另一个平台产生相反结果。最终保留的应是对目标设备和真实场景有收益的改动。

参考资料

本文根据以下资料整理撰写,详细规范与版本行为请以原文为准。