Unity 2017 Game Optimization 讀書筆記(2)Scripting Strategies Part 2

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,這玩意也會不斷的產生開銷,所以我們要權衡是否降低調用頻率帶來的好處值得這麼幹。

Coroutine 消耗大概是3倍
Coroutine消耗大概是3倍
​​​​​​

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的概念,這個是非常重要的,在之後會非常經常的提及,因爲內存的優化主要就是跟這倆貨打交道。

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章