对象复用是 用空间换时间的一种典型的做法,对于Unity来说虽然引擎内部有GameObject的对象池,但是
这只是Native层的,到了Managed层还是可以继续优化的。通过Profiler能够发现实例化GameObject 还是比较消耗CPU的。
Unity中对象池主要有3种,
1.普通的C# class的对象池
2.GameObject 的对象池
3.byte[] 的内存池
先说结论:
1.普通的C# class的对象池和byte[]的内存池,复用后性能提升很大很大很大。其中包括了GC。
2.GameObject 的提升就比较低了,大约只提升了50%。CPU消耗中约40%是发生在Alloc的内部操作以及复用的一些控制,另外60%消耗在GameObjet.SetActive上,这60%可根据实际情况定向优化掉。
普通的C# class的对象池 和 byte[] 内存池比较简单,不过为了尽可能避免泄露,最好 IDisposable 和using结合起来使用,可做到多线程支持。byte[]可以用分段来处理,适当的增加一些冗余,尽可能减少粒度。
Unity的大部分组件(如Rigidbody Collider)只能挂载在GameObject之上,这意味着无论什么样的客户端框架,都避免不了MonoBehavior脚本的交互,这一点就意味着Start OnDestroy等生命周期控制的语义就变了。这样的话GameObject的对象池就复杂多了。为了解决这个问题,就要制定一些规范来约束MonoBehavior的行为。
为了避免泄露和加强健壮性,除了制定一些规范,还要做一些容错,如类似于GC行为的 Collect 或 Resources.UnLoadUnUsedAsset 的操作。在适当的时机检测一下使用量。这个在GameObject对象池中尤为重要。