UNITY3D 代码需要注意的地方

在解决资源引起的性能之后,我们着手解决代码层的问题
  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分钟以上一次.



1.AddComponent
一个消耗时间8ms左右,非常费。考虑改成依赖注入
2017/7/27
2.String操作
http://www.cnblogs.com/rainbowzc/p/3687193.html
1.使用StringBuilder做字符串连接
String类型是值类型变量,使用 + 操作连接字符串将会导致创建一个新的字符串。如果字符串连接次数不是固定的,例如在一个循环中,则应该使用 StringBuilder 类来做字符串连接工作。因为 StringBuilder 内部有一个 StringBuffer ,连接操作不会每次分配新的字符串空间。只有当连接后的字符串超出 Buffer 大小时,才会申请新的 Buffer 空间。
2.避免ToUpper和ToLower方法
String类型是值类型变量,ToUpper和ToLower会导致创建一个新的字符串,如果频繁调用,则会频繁创建字符串对象。
3.最快的空串比较方法
最快的方法是str.Length == 0
其次是str == String.Empty或str == ""
  注:C#在编译时会将程序集中声明的所有字符串常量放到保留池中(intern pool),相同常量不会重复分配。(指的是这个"")
2017/7/30
3.NET内存相关

有时间把这个翻译了
https://www.red-gate.com/products/dotnet-development/ants-memory-profiler/learning-memory-management/memory-management-gotchas
2017/8/26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值