UNITY3D手游优化2 代码需要注意的地方

发表于2016-12-20
评论1 1.7w浏览
  在解决资源引起的性能之后,我们着手解决代码层的问题
  UNITY3D/MONO的坑是比较多的,前期制作好代码规范,后面会少走很多弯路。

一、MonoC#篇
  1、不要使用foreach
  每个foreach调用,大概会分配30B左右的内存.大量的调用会触发GC
  替代方案,对于数据结构list:
    For(inti=0;i
    dosth();
对于其他非线性的数据结构:
    var etr = dii.GetEnumerator();
    while (etr.MoveNext())dosth(etr.Current);
  2、尽量使用stringbuilder替代string.并且new stringbuilder(cap) 尽量预先分配好合适大小的内存.string.format的底层实现是stringbuilder,可以使用。
  3、c#对于返回的变量,基本都是新new出来的.尽量少使用.比如
  ICollection.ToArray(),会返回一个新new的T[]对象
  ToString(),会产生string临时对象
  4、不要使用Lambda表达式.每次都会有52B的内存分配. 定义函数替代之
  5、很多数据结构 比如list/Dictionary都提供了初始分配cap大小的构造函数.根据实际的需要,优先使用这样的构造函数来初始化数据结构
  6、尽量不要使用值类型到System.Object的转换.c#俗称装箱.
类似这样的转换 System.Objectobj = (System.Object)int_i;每次都会有10B的内存分配.这样小内存的频繁调用,很容易触发GC.
如果实在是必须使用,也首先考虑使用类似于MGAME的SimpleGenericParam这样的实现替换之.
  7、不要以枚举/自定义struct作为Dictionary的key.尽量考虑用基础类型int等来替代.
他们的GetHashCode都有装箱操作,每次调用TryGetValue查找都会有内存分配.
  8、尽量减少new的次数,预分配/成员变量替代临时new变量等.
  9、尽可能避免使用LINQ。部分功能无法在某些平台上使用,会分配大量GC Alloc。而且我很讨厌LINQ的一点就是它有可能在某些情况下无法很好的进行AOT编译。比如“OrderBy”会生成内部的泛型类“OrderedEnumerable”。这在AOT编译时是无法进行的,因为它只是在OrderBy的方法中才使用。所以如果你使用了OrderBy,那么在IOS平台上也许会报错。
  10、尽可能避免使用delegate以及lambda
 
二、UNITY引擎篇
  1、不要使用Object.name,Unity每次使用都会重新new string返回 ,同理的还有component.name
真需要的话,请缓存再用
  2、if(gameobject.tag==”player”)改为gameobject.CompareTag(”player”).前者会额外有内存分配
这里可以总结成所有的UNITY引擎返回的串都要谨慎使用(包括及不限于:gameobject.transform,gameobject.name等)
  3、对于在Update中使用的很频繁的类似属性,建议直接保存子对象而不是gameobject。如把gameobject.transform换成直接访问        transform。
  4、只读的话,用sharedMaterial替代material
  5、控制StartCoroutine的次数
开启一个Coroutine(协程),至少分配37B的内存.Coroutine类的实例 -- 21B
  6、谨慎使用GetComponent系列函数
GetComponent函数如果没有找到组件,每次调用大概会分配60KB内存.
对于子结点比较多的GameObject调用GetComponentInChildren,如果调用比较深才找到,额外分配的内存甚至会达到1M多.
要求去除所有的在每帧Update中的GetComponent操作,如果有需要用到请在缓存再用。
  7、Shader的property去取不要用名字,用Shader.PropertyToID
  8、不要有空的Update/LastUpdate之类的UNITY默认回调函数.
 
三、其他注意事项
  1、TDR协议发送和接收有大量的GC,可以引入对象池解决
  2、视口外的逻辑尽量简化.表现性逻辑可以完全不走.可以比较大的提升性能.
  3、behaviac的实现,在传递behaviac定义的值参数时,会有装箱GC.写多个重载函数替代泛型实现可解决.
  4、AI可根据不同的类型定制不同的更新频率.比如普通小怪就不需要像英雄那样更新频繁.
  5、帧同步游戏,可以把逻辑帧的更新分拆,插入到两个逻辑帧中间的渲染帧去做.
  6、UGUI的Rebuild很费.可以通过独立更新频繁的Canvas . Canvas. renderMode 修改成 RenderMode.WorldSpace来改善
  总的来说,代码层面最终GC的频率需要控制在2分钟以上一次.

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引