Unity 优化相关小结
下面这个链接很全了,看这个总结就好了。
移动游戏性能优化通用技法
背景
项目从 Unity2017 升级到 Unity2020,界面打开多了会很卡。由此,时隔一年,再一次用到了性能优化。为什么是时隔一年,中间都不优化的嘛?“Optimization for the sake of potimization is a waste of time”,为了优化而优化是在浪费时间,如果游戏在目标设备上正常运行,没有卡顿等异常表现,那么就不需要去优化,而是做其他更高优先级的事儿。
步骤
- 通过各种调试器发现项目有哪些表现问题
- 列出优化任务,优先处理收益最高的
- 如果表现已经很好了,但是任务还没有清空,那么不用管了,还是停下来做其他更优先的事情吧
- 如果表现还是有问题,那么就要记录每次修改后,调试的结果,通过前后观察比较来理解中间发生了什么,是谁在捣鬼(开启名侦探柯南模式
性能问题的类型
尖峰
尖峰的表现是游戏帧率突然下降,画面突然卡住。
尖峰的形成主要是在一帧内执行了复杂或困难的运算导致耗时过高。
垃圾收集引起的尖峰
内存垃圾到达限制,或者内存不足,会触发垃圾回收,整理释放没用了的内存。触发频率受每帧产生的垃圾数量影响。解决这个问题的唯一方法就是减少垃圾回收,在开发过程中,就应该注意避免。
每帧耗时
每帧耗时过高的表现是游戏帧率低。
帧耗时取决于每帧做的运算和操作。
加载耗时
加载耗时包括游戏打开时和加载的耗时,比如切换场景的时候。
要解决这个问题,主要时减少需要加载的内容体量,可以是提前预加载或者减少加载内容的复杂度。
内存占用
RAM(Random Access Memory)保存游戏运行时需要的所有数据。
VRAM(Video Random Access Memory)保存要被显卡绘制的模型和纹理数据。
CPU使用RAM,GPU使用VRAM,如果内存不足,则会出现闪退。
如何减少内存占用:
- 减少数据的复杂度和纹理的分辨率
- 减少独用的资源(多多复用)
- 使用缓存池
分析
分析过程即通过分析性能数据,找出引起性能瓶颈的地方。
Unity 提供了几种分析工具:
Profiler,
Profile Analyzer (package),
Frame Debugger,
Memory Profiler (package),
Physics Debugger,
UIElements Debugger.
Unity 优化:提示&技巧
代码
Events
使用C# Events 而不是 UnityEvents。
Strings
不要在 Update() 中拼接2个 string,因为每次都会分配内存,产生内存垃圾。比如倒计时,可以把它分成两个 text 组件,一个固定文字,一个数字倒计时。
Unity UI(UGUI)
Canvas
Unity UI 的基本元素是 Canvas。这些 Canvas 容纳所有 UI 元素,其中某个元素发生变化时,整个 Canvas 会被标记为脏,需要重新绘制。因此可以按照变更频率来划分 Canvas。
Graphic Raycaster
当收到点击事件时,Unity 需要检查所有可能被触发的节点是否要处理点击,因此不需要处理的节点就不要勾这个选项。
Camera.main
尽量为 Canvas 指定具体 Camera,否则会自动调用 Camera.main,这个方法会调用 Object.FindObjectWithTag,回产生GC。每当发生点击之类的事件时,都会触发。
缓存 UI
这是用来避免 UI 频繁创建销毁的有用方法。但是可以更进一步的优化,在回收前先隐藏,在复用时,先更新节点,再显示它,这样避免 hierarchy 被标记脏两次,但是不太好处理就是了,一般情况不需要优化到这步。
隐藏 Canvas
有许多方法可以隐藏 UI,但是大部分方法只要 Canvas 是开启的,仍然可能触发脏标记。如果只是想要隐藏 UI,可以只关闭他们的 Canvas,可以避免 UI 的 OnEnable/OnDisable。
其他:
- 文本少用 Best Fit 和 Rich Text
- 文本少用 outline 或 shadow
- 图片少用 tiled,会增加顶点
- 尽量摊开节点,少嵌套子节点
- Canvas 不要勾选 Pixel Perfect
- Mask会多出2个DC(1设置模板缓存,2还原模板),而且会打断上下节点的合批,但是Mask与Mask之间可以合批;Mask2D不会新增DC,但是只能子节点内部合批,无法与外部节点合批
内存管理
Unity 会自动进行内存管理,但是当释放内存的时候,必然会引起帧率下降。
垃圾回收(GC)
主动垃圾回收
在合适的时机主动调用垃圾回收,比如场景过渡时。但是不建议主动回收,应该通过其他方式,减少垃圾的产生。
System.GC.Collect();
缓存
缓存一个经常用到的数据,而不是每次都去计算获取。比如Camera.main
或者gameObject.transform
会引起一点开销。
对象池
缓存经常使用的某一种类型的结构。
纹理设置
音频设置
提前分配内存
在初始化提前申请需要的堆内存,然后释放,这样避免运行过程中自动扩充内存带来的卡顿。
减少 Draw Calls
静态合批
使用同个材质的对象,并且勾上 "Static"。
Frustum Culling
Occlusion Culling
LOD levels on 3D objects
Convex Mesh Collider for Complex Objects
参考
Unity性能优化 — UI模块
Unity Optimization Tips: Mobile & Desktop
7 Unity GUI Optimization Tips For Your Game
Unity UGUi优化分享及注意事项
UGUI層級分配與效能測試
UGUI和特效模型混排的解决方案