1、FPS均值较低

CPU性能优化方案

频繁调用的Camera.main

建议脚本做好Main Camera的Cache。Camera.main实际为GameObject.FindGameObjectsWithTag(“MainCamera”)调用,主要因为引擎无法得知用户通过脚本设置的MainCamera,CPU消耗较高。

脚本中大量UnityEngine.Object的判等操作

建议改为用InstanceID来判断即Object. GetInstanceID,运行期间保证唯一。 因为Object的判等还有额外的耗时操作,而Int类型的判等就非常快速了。同理,使用Object作为key的数据结构也建议改用InstanceID做key。

用于查询操作的数据使用list数据结构

List线性结构Contains的耗时非常高,建议改为hashset,hashtable之类的查询操作效率高的数据结构。

加载资源时每帧从Assetbundle加载的Asset数量没有限制

在场景内每帧从Assetbundle加载的Asset数建议限制在2到5个,数量高时耗时过长容易造成卡顿。

模型导入设置[Rig]选项页中Optimize GameObject没有勾选

建议开启Optimize GameObject,这个选项可以把SceneManager中用于skinning的节点都去除,节省了场景节点树更新以及查询的CPU消耗,对于需要做挂点的节点可以添加到例外列表中。

使用第三方音频插件时没有禁用Unity内置音频

不需要使用Unity内置音频模块的时候,建议Editor中通过勾选Edit->Project Settings->Audio->Disable Unity Audio来完全禁用FMOD模块,避免不必要的CPU消耗。

GPU性能优化方案

特效渲染的Pass数量较多

一些特效的渲染可以合并到同一个Pass以节省GPU开销,另外RenderTexture在可以共用的情况下尽量共用。

同屏面数过多

同屏面数建议在20W以下,较优情况是控制在10W以内。

UI元素在需要隐藏的时候使用了设置Alpha为0的方式

实际上GPU依然需要对UI mesh进行渲染,建议不要通过设置Alpha为0的方式来隐藏UI。

当使用网格作为地形时,适当切分地形网格

在网格顶点数很高情况下需要依靠硬件裁剪来剔除顶点,比较消耗GPU性能,建议按照大概的同屏可见范围来切分地形网格。

UI元素过多依赖多层元素的混合来达到美术效果

这样会造成较多的Overdraw,建议尽量通过预制纹理来做到想要的效果。

2、脚本逻辑(Update)耗时高于渲染(Camera.Render)耗时

一般情况下BehaviourUpdate耗时会比Camera.Render耗时低,多人战斗时可能会高些。

建议检查CPU耗时较高的函数,优化代码计算复杂度,降低脚本逻辑耗时。

3、RenderTextures内存较高

检查是否有固定分辨率的较大RT,应该根据设备实际分辨率设置RT分辨率;考虑不同效果中使用的RT是否可以共用;UI中使用的RT考虑是否可以用实际模型替代。

4、Mono堆内存较高

通过优化每帧GC量较高的函数以及某帧出现大量GC的函数来间接减少mono内存池出现内存不足而自动扩展的情况。

 5、纹理资源内存较高

纹理没有压缩

在很多情况下,美术会觉得纹理压缩后效果不理想。我们建议的是:

可以把原图的分辨率长宽都扩大一倍,保持原有压缩格式。这样压缩过后的文件还是比不压缩的文件要小,并且视觉效果可以得到较大的改善。

纹理导入设置中的 Read/Write Enabled 处于勾选状态

开启纹理导入设置中 Read/Write Enabled,纹理在传到GPU之后,CPU端的数据也会一直保留在内存中。因为在移动端显存共享内存,会导致内存占用加倍。因此需要注意是否有需要在CPU端访问的纹理,比如:需要通过脚本获取纹理像素的情况下,就要开启纹理导入设置中的 Read/Write Enabled。

纹理资源参数

纹理资源的长度、宽度、格式及是否有mipmap等参数都会影响其内存占用,对于纹理资源的参数,我们的建议值为:

纹理的长度和宽度最好保持在2048以下,格式为压缩格式,并且不需要的情况下不使用mipmap。

其他

图集atlas的空间是否充分利用。

 6、网格资源内存较高

模型文件导入设置中 Read/Write Enabled 处于勾选状态

除了需要脚本中访问的网格,作为网格碰撞器中的网格,脚本中用StaticBatchingUtility.Combine静态合批的网格,以及粒子系统发射的网格之外,其它模型建议不要勾选此项 ,否则会在内存也保留一份网格实例占用内存。

模型文件导入设置中 Read/Write Enabled 处于勾选状态

检查模型网格顶点数是否过高;是否有较小的物件使用了较多的顶点,对于纹理资源的参数,我们的建议值为:

对于动态物体,面片数建议在300-2000,材质数建议在1-3。

对于静态物体,顶点数建议在500以下,混合纹理数建议在5以下。

7、Mono空闲内存(堆内存-已用内存)较高

Mono空闲内存越大说明有越多的不必要内存池扩展,比如说在同一帧内有加载大量资源,实例化大量对象等,可能让内存池瞬间膨胀的操作。

由于Mono本身的机制,这部分空闲内存并不会被操作系统回收,导致内存的浪费,因此建议对Mono空闲内存较高的情况进行优化,检查是否有GC Alloc突然变高的函数并优化,避免同一时刻大量的Mono内存分配操作。

8、GC Alloc较高

GC Alloc越频繁,量越大,由于Mono内存池可用内存不足导致的GC.Collect(造成卡顿原因之一)调用就越频繁,并且可能引起mono内存池不必要的扩展,因此脚本函数的GC分配量是既影响CPU也影响内存的重要参数。对于GC Alloc,我们建议的参考数值为:

对于基本每帧都会进行GC Alloc的函数,GC Alloc大于2KB的建议都确认下是否有可能把每帧内统一分配的临时变量抽取为类成员变量。

对于偶尔进行GC Alloc的函数,GC Alloc大于50KB的建议都确认下分配的数据结构是否有优化空间,GC Alloc是否可以分摊到多帧内。

 

值得注意的是,在移动真机上,垂直同步关掉发现不起作用,Device.Present依然耗时,CPU开销大,该项过高主要是两个原因:【借鉴他人建议】
(1)如果当前帧的CPU开销小于等于33ms,那么Device.Present基本上是硬件上垂直同步导致的;
(2)如果当前帧的CPU开销高于33ms,那么Device.Present过高表示你的GPU压力过大,或者某个子线程的CPU开销过大。

一般第二种可能性较大,检查是不是自定义shader造成GPU压力过大,可以根据cpu与gpu的优化方案进行优化。

 

好久不整理了,以上建议来自Wetest工具。