Unity 性能优化及一些其他技巧

更新日志:(由于此篇会长期不定时更新,所以添加一个“更新日志”)
Unity 的托管内存优化 2017.09.08
Xcode调试及遇到的问题 2017.09.08

下面片段式的总结一些常用的性能优化技巧和一些常见问题:

  • 模型导入要使用FBX文件,并且关闭 Read/Write Enable。强调一下,如果打开 Read/Write Enable 会导致内存翻倍。

  • 如果模型中不存在动画数据 或者 这个模型计划就是不带动作的,模型的导入设置中的 Animation Type就选择None。如果不这样做,即使这个FBX里面没有动画数据,也会默认添加一个Animator的组件,会增加了内存的占用。

  • FBX导入的时候,如果不使用一些Normalmap等特性,建议关闭。你如果开了Normal Tangent导入也都是浪费了内存空间,一般都是在项目开始初期决定用不用Normal Map,如果不用的话以后可以把这个关闭掉。

  • 音频设置方面,建议iOS使用mp3,安卓采用vorbis。

  • 音频的采用率一般20k就够了

  • 音频文件如果不考虑双声道,最好压缩成单声道。音频文件还要考虑是单声道还是双声道,一般情况下用单声道效果是足够的,我们把它压缩成单声道也可以减少内存的占用。

  • 建议对小音频采用Decompress On Load这种模式的加载方式。因为对小的音频文件的话,你在加载的时候解压缩一次,这样播放的时候不需要重新解压缩,如果每次解压缩会导致手机发烫、续航减少等等问题。

  • 不推荐使用Resources文件夹。Unity官方已经不再推荐使用Resources文件夹了,而且未来可能把这个功能关闭掉。因为你把资源放在这里面的话,它是有几个缺点的,其中一个缺点就是在游戏启动的时候,它第一步会把Resources文件夹内的所有文件构建成索引,以便于你后面可以在这些索引里面动态的加载资源。这样做导致游戏启动比较耗时,会发现启动黑屏的时间很长,这样体验实在不好。还有一个缺点是,构建索引会占用更多系统的内存资源。

  • 不建议使用OnGUI。OnGUI是Unity老的UI系统,现在不建议使用OnGUI了。

  • Unity 5.2之后,UGUI优于NGUI。虽然NGUI很强大,但还是有它的不足。因为它使用C#开发,会导致堆栈的内存分配,运行时会导致内存的操作。

  • 少用后期镜头特效。后期特效其实有多个问题,首先它的GPU消耗比较高,另外一个消耗是会导致你的内存消耗非常大,因为每个特效都有可能分配你一个全屏幕大小的一个RenderTexture。而RenderTexture因为要用来实时渲染,所以是不能压缩,不像普通的游戏纹理可以使用ETC或者PVRTC格式压缩。所以它对内存的占用非常高,我们经常看到有的游戏后期特效分配了几十兆甚至更高的内存。

  • 不需要Alpha通道的图片,一定要把Alpha通道都关闭掉。

  • 发现PutGeometryJobFence耗时较多就代表了“对网格体顶点进行操作的次数太多”。一般是因为使用了很多粒子系统,LineRenderer或者Trail,就会产生这个消耗。

  • 如果是移动端的产品,尽量使用Mobile或者Unlit下的shader。要注意的是,特效人员在制作特效的时候,也需要使用这两个目录下的shader。不然会多少产生一些兼容性和内存问题。

  • 移动端产品的最大粒子数建议小于200,每个粒子发射器的最大粒子数建议不超过50,不是必要的情况不要开启粒子的碰撞。

  • 移动设备上,Drawcall的数量建议不超过100。很多人都会问到这个问题,其实这个是没有一个定数的,我这里给出的也只是一般参考。具体一个游戏在手机端卡不卡,不是Drawcall的数量越少就越流畅的,因为流畅性还受限于GPU的带宽等其他东西。

  • 隐藏物体尽量不要使用GameObject.SetActive这个API,可以使用更改物体的Layer、移动到摄像机外、改变层级等等方式。因为GameObject.SetActive这个API会导致物体的顶点重构,甚至造成卡顿。

  • 光源的性能占用顺序:聚光灯>点光源>平行光

  • 注意Renderer.material和Renderer.sharedMaterial的区别。如果你需要通过脚本来访问材质属性,那么你就要注意,如果改变Renderer.material将会造成一份材质的拷贝。所以,应该尽量使用Renderer.sharedMaterial来保证材质的共享状态。

批处理

  • 动态批处理仅支持小于900顶点的网格物体

  • 如果你的Shader中使用顶点位置,法线和UV值三种属性,那么你只能批处理300顶点以下的物体(这个限制不知道在Unity5中还存不存在)

  • 如果你的着色器需要使用顶点位置,法线,UV0,UV1和切向量,那你只能批处理180顶点以下的物体(这个限制不知道在Unity5中还存不存在)

  • 统一缩放尺度的物体不会与非统一缩放尺度的物体进行批处理。使用缩放尺度(1,1,1)和 (1,2,1)的两个物体将不会进行批处理,但是使用缩放尺度(1,2,1)和(1,3,1)的两个物体将可以进行批处理。

Unity 的托管内存优化

  • 尽量不要动态的Instantiate和Destroy Object,使用Object Pool,也就是对象池

  • 以帧为单位来操作的函数里面,尽量不要进行堆栈分配内存。因为Unity使用C#语言托管了内存的释放,导致开发者不能选择在什么时间去释放内存。而如果使用C#的GC操作又会非常耗时,特别是在场景非常复杂的时候,它需要遍历场景中所有的对象。很多游戏你玩的过程当中发现游戏卡顿都是内存GC导致的卡顿。

  • 不要动态的产生、链接字符串。下面的代码是几个GC“噩梦”。 String的相加操作,会频繁申请内存并释放,导致gc频繁,使用System.Text.StringBuilder代替。

public string StringExample(int[] array)
{  
   string line = array[0].ToString();  
   for (i = 1; i < array.Length; i++) line += ", " + array[i].ToString(); 
   return line;  
}
  • 尽量减少函数调用栈。用x = (x > 0 ? x : -x);代替x = Mathf.Abs(x)

  • 尽量不要在函数中新建Array或者List,而尽量采用传入Array或者List再进行修改的方式。

  • 对实时更新要求不高的地方,Update处理可改为每N帧处理一次。如下:

void Update() 
{ 
  if(Time.frameCount % 5 == 0) //这里是每5帧处理一次
  { 
    // TODO Something
  }
}
  • 尽量不要在Update, FixedUpdate, LateUpdate等每帧处理的函数中开辟新变量。这点在上面也提到了,“尽量不要在以帧为单位来操作的函数里面,进行堆栈分配内存”。示例如下:
void Update() 
{ 
  int a,b,c;
}

改为:

int a,b,c;
void Update() {}
  • 主动回收垃圾,给某个 GameObject 绑上以下的代码。(但是这样做会有一些弊端,最优的情况是“每次GC回收的间隔越大越好,一个很好的项目应该做到500-1000帧进行一次GC”,但是,你要考虑到C#是会自动进行GC回收的,只有代码各方面最优的情况下,才能尽量少的进行GC。)
void Update() { if(Time.frameCount % 50 == 0) { System.GC.Collect(); } }
  • 尽量缓存用到的Componment组件,减少GetComponent的调用。每次GetComponent或使用内置组件访问器(如transform.Translate(0, 0, 5)中的transform就是内置组件访问器)会产生明显的开销。
void Update () {  
    transform.Translate(0, 0, 5);  
}  

//转换为:  

private Transform myTransform;  
void Awake () {  
    myTransform = transform;  
}  
void Update () {  
    myTransform.Translate(0, 0, 5);  
}
  • 适当使用结构(struct)来代替类(class)。结构变量主要存放在栈区而非堆区。因为栈的分配较快,并且不调用垃圾回收操作,所以当结构变量比较小时可以提升程序的运行性能。但是当结构体较大时,虽然它仍可避免分配/回收的开销,而它由于"传值"操作也会导致单独的开销,所以此时它会比等效对象类的效率低。

  • 尽量使用内置数组(也就是尽量使用string[]而不是List),内置数组比ArrayList和List等快上非常多。虽然ArrayList或Array类很容易使用,你可以非常容易的进行添加删除修改等操作,但是内置数组会比ArrayList和List快上非常多。 内置数组是直接嵌入结构数据类型在一个紧密的缓存里,而不需要任何额外类型信息或其他开销。因此,在缓存中遍历它是非常容易的,因为每个元素都是对齐的。



今天就先写到这里,有空再更。

你可能感兴趣的:(Unity 性能优化及一些其他技巧)