使用Profiler的时候经常会看到一些GC Alloc,GC Alloc多了会影响帧数。
产生GC的本质是在heap上频繁申请内存,比如在Update()中使用new 关键字实例化reference type 对象,而像Vector3 struct 这类 value type在栈上分配内存,则不会产生GC。 但有时候在一个脚本中并没有使用任何一个 new 关键字,也会产生GC。以下几条guidelines能够帮助消除游戏中产生的不必要的GC。
1.避免使用 foreach
使用foreach的时候会隐式调用 GetEnumerator(),在heap上生成一个enumerator,导致GC。 建议使用 for 和 while来做循环迭代或者显式调用GetEnumerator(),代码如下:
foreach的使用起来比较明晰和简便,可以在非 Update、LateUpdate、FixedUpate 调用频率高的场合使用。
2.避免使用Update中使用string
C# 里的string是immutable的,会在heap上分配内存。在Update里操作string 会造成很大的GC。所以不要做在Update里给一个Label赋值这种事。
3.使用struct或者enum作为dictionary key会分配内存
使用struct或enum做key的dictionary,在使用TryGetValue()或者键值访问时,会分配内存。 以下方法可以避免这种情况:
1) 自定义的struct作key,struct需要实现 IEquatable
2) enum 作key麻烦一些 申明一个Comparer的struct
初始化字典
4.避免Update中new 引用对象
Update里不能new 引用类型。Vector3、Quaternion、Struct这种值类型可以。堆上分配内存的都不行。
5.避免高频率使用playerprefs的set get
Playerprefs set 和get 是文件读写操作,高频操作会影响性能。这个可能不会产生GC,但很耗CPU.
6.不要使用NGUI的Property Binding
不要使用NGUI的property binding,她的内部使用反射机制实现的,效率极差。
7.不要忘记取消注册的事件
基本上忘记卸载注册的事件会导致内存泄漏,使用NotificationCenter注册的事件也要记得remove
8.不使用LINQ命令
因为它们一般会分配中间缓存,而这很容易生成垃圾内存。
9.不要直接访问gameobject的tag属性
比如if (go.tag == “human”)最好换成if (go.CompareTag (“human”))。因为访问物体的tag属性会在堆上额外的分配空间。
–EOF–