1. Share calculation output
和上一个Tip很像,可以缓存计算结果或者各种信息,避免多次重复的计算,例如在场景里查找一个物体,从文件读取数据,解析Json等等。
容易忽略的点是常常在基类了实现了某个方法,在子类里只是不断的使用而不再去注意基类里的这个方法是否消耗很大,如果遇到性能问题可以通过Profiler定位函数,进而优化,作者的建议是除非真的遇到了性能瓶颈,否则提前的优化并没有必要。个人理解是过度的优化未必是合理的,会影响代码的可读性以及简洁性,需要和性能达到合理的平衡。
2. Update, Coroutines, and InvokeRepeating
我们经常使用Update去处理一些事务,但是其实有很多时候并没有必要需要这么频繁(每帧)比如下边这个例子:
并没有必要每帧都去调用AI系统处理,可以这样写减少调用频率,降低CPU开销
也可以使用Coroutine来完成这个功能,千万别搞混Coroutine和线程,它俩完全是俩码事,Coroutine是跑在主线程的。
这么写的好处就是可以根据_aiProcessDelay变量随心所欲控制调用频率,但是也有很多缺点。
1.Coroutine 会有额外的CPU开销,大概是3倍于普通函数,而且会有额外的一些内存消耗(用来存储状态变量等)。Coroutine会不停的调用yield,这玩意也会不断的产生开销,所以我们要权衡是否降低调用频率带来的好处值得这么干。
2.一旦初始化后,Coroutines就放飞自我了,Component甭管是否disabled掉,它们会一直的在调用。
3.当GameObject 变成inactive时(whether it was set inactive or one of its parents was),Coroutine 会自动挂掉并且再也不会自动启动,即使重新变成active也没辙,停了就别想让我自动活过来。
4.改成Coroutine只是降低了频率,如果函数消耗特别大,即使调用次数变少,被调用的那一帧依然会产生很大消耗,造成帧率下降。所以对于是因为函数消耗大的情形,使用coroutine也没鸟用的,只能去优化该函数降低消耗才是正途。
当使用Coroutine时,有多种yield 种类可以供我们选择。包括WaitForSeconds 和 WaitForSecondsRealTime等(WaitForSecondsRealTime不受Time.Scale影响)。如果Coroutine够简单,可以直接改造成使用InvokeRepeating,它使用起来更简单而且消耗会稍微小一丢丢。
InvokeRepeating和Coroutines的最主要区别是InvokeRepeating已经完全独立于MonoBehaviour和GameObject的状态,放飞自我的更狂野,想停下InvokeRepeating, 只能通過CancelInvoke函数或者直接Destory掉相关的Monobehaviour或者GameObject,disable掉Monobehaviour或者GameObject都拦不住这个已飞起来的InvokeRepeating
3. Faster GameObject null reference checks
GameObject 和 Monobehaviour对于传统的C# object是很特殊的,它俩在内存中会有两种形式,一种是存在于Managed memory(和C#代码存放的内存一样 Managed Code),一种是存在于Native memory(Native Code),更多的原理将在第八章中介绍。这里我个人解释几句,Unity的内存可以分为两种,托管堆(Managed),和Native。托管堆是我们写的C#代码,Native是Unity底层的代码,Unity底层其实是C++写的。像GameObject 和 Monobehaviour这种由Unity提供的类,它们将会在两种内存中存在,数据可以在这两种内存中传输,但是每次传输都会有开销。这种行为可以叫做Native-Managed Bridge,就想Native和Managed两部分内存的桥梁一样,当需要从这部分内存传到另一部分时,就会产生内存数据的copy,也会需要GC。
对于判断GameObject是否为Null这件事,一种简单写法是:
但是这种写法会触发Native-Managed Bridge,GameObject从native到managed。所以开销会大一些。更有效的写法是:
但是其实经过测试,即使直接用null进行判断,速度也没慢到哪去,只是快和更快一点的区别,真的是了胜于无。所以这里作者原话意思是也没多点性能提升,但是重要的是引入了Managed和Native的概念,这个是非常重要的,在之后会非常经常的提及,因为内存的优化主要就是跟这俩货打交道。