如何正確高效的查找遊戲「卡頓」原因?

背景:我在一家創業公司,我們開發了一些獨立的小遊戲。最近在做的一款小遊戲,使用了 Unity 引擎,在研發快要完成時,我們忽然發現:遊戲偶爾會卡一下,間歇性的卡頓。我們的策劃表示:會這樣卡頓,堅決不能發布!

於是我們開始查找遊戲「卡頓」的原因,用了這幾種方法:

1.用 Unity 自帶的 Profiler:發現卡頓時,尖峰的地方佔用最高是 Overhead,佔了90%,沒找到有用的信息;

2.根據經驗,找可能會卡的點,比如說載入大資源等等,但是這些都沒有,也沒有網路請求;

3.Google,StackOverflow,Unity Forums:大家的情況各不相同,但是沒有人遇到我們這種情況;

4.做減法:從卡的版本開始,checkout 版本,把版本一步步往回退,找到了不卡的版本,然後把 Feature 一步步加回來。發現在加入碰撞「BoxCollider」後,開始會出現這種卡頓,但是這太奇怪了,難道說 Unity 的碰撞有問題嗎?當然,這樣的推斷我們也知道不靠譜,因為加 Feature 的過程中,可能是多個部件共同合作引起的卡頓,不一定是 Unity 的問題。

以上,大致就是我們排查這個「卡頓」原因的過程,但是最後我們得到的結果讓人懷疑,實在沒有說服力。

因此,我想請教諸位,我們用的這些辦法,是否有一些愚蠢的錯誤,或者,其實有更高明更高效的排查「卡頓」原因的方法,感謝諸位。


首先打開profiler,查看所有凸起的線

一般遊戲內卡頓的地方

  1. 遊戲戰鬥過程中在載入資源文件
  2. NGUI中圖集太亂導致drawcall彪漲

  3. NGUI中active/unactive導致重建drawcall生成大量的資源
  4. 頻繁創建對象刪除對象,沒有緩存。
  5. unity自身的一些bug,有時候可以看到物理引擎計算的量很大。
  6. 使用了更精確但更耗時的判斷如meshcollider
  7. 所有邏輯都使用unity主線程處理
  8. 使用過多複雜的渲染,如一些實時GI或攝像機渲染效果加強
  9. string串接foreach,getcomponet等問題

解決方法

  1. 在遊戲戰鬥開始時前載入所有用到的資源,不要在戰鬥過程載入資源,因為unity是單線程的模式,如果沒有使用非同步線程做載入或一開始進入場景時載入,這個問題就很突出了。

  2. NGUI為了減少GPU狀態切換的消耗(比如切換material),把相同material的UIWidget合併,減少Draw Call的數量。這一步是基於UIPanel做的,合併UIWidget的代碼可自行查看UIPanel.cs的FillAllDrawCalls()函數,原理如下圖,盡量分好層次如背景框,按鈕等。

  3. NGUI中,active/unactive會刪除重建材質drawcall,如果界面內容稍多一些,會導致內存分配,甚至出現drawcall的死循環,目前比較正確的做法是,設置在屏幕坐標外部,然後關閉所有NGUI腳本的運行,NGUI作者的回復截圖。

  4. 使用對象池緩存一部分頻繁使用的資源,不必每次都創建卸載。
  5. 更新新版本,設置好物理引擎參數。
  6. 如果沒有必要的話,盡量使用速度較快的碰撞檢測,入boxcollider。
  7. 應該合理分離主線程與邏輯線程的關係,比如一些演算法採用非同步執行的方式,網路數據的解析,載入等,使用代理來把必要的邏輯切換到主線程,不必要的邏輯使用邏輯線程,可以通過一個MonoBehaviour的update來執行代理邏輯

  8. 有些手機根本無法運行複雜的渲染,能簡單盡量簡單。
  9. 字元串串接使用stringbuilder不使用+,頻繁foreach最好用for代替,緩存已經取到的componet.


分享一點我們自己在做性能優化時的小經驗:

在Unity Editor模式下運行,有部分Overhead是由運行時的場景編輯器導致的,採樣的時候可以先把「Scene」關掉。

用Profiler採樣時,首先重點關注CPU佔用率高的方法,並且優先打擊

關注內存分配「GC Alloc」,每幀超過100B的內存分配都需要解決,否則這樣的的內存分配累積後就會引起GC,很容易引起卡頓


檢查一下所有static colliders是不是確實沒有變化;假如每幀都有某個static collider參數有變化,unity會在每次變化都重新計算所有靜止對象cache,如果有這樣的情況,給加個rigidbody改成動態的


mesh collider還是boxcollider?


碰撞 BoxCollider 的 Overhead ?

當年遇到了個扯談事情,不知道是否相關。

Unity處理 動態物理的消耗比較高,如果大量BoxCollider都在運動,消耗會相當驚人。

如果是類似跑酷、飛機之類的遊戲,千萬弄成 人物/飛機 運動,而不是 背景捲軸運動。


Mac上有Instruments

Unity Profiler上看不到的東西,可以build一個iOS的版本用Instrument看。

根據你提供的信息還是很難推測。

卡頓發生的時候執行了什麼操作?切Scene?大量創建、銷毀對象?


開deep profiler


如果你用的是4.x版本,可以在collider的物體上再加一個rigidbody. 這是老版本物理系統沒有優化好的地方。5.x版本升級到了最新的物理系統,可以忽略這個問題。


推薦閱讀:

如果BUG和電腦病毒入侵到現實世界裡,TA們會長什麼樣?
自學編程最大困難是什麼?
openfoam需要多少linux知識?
如何列印出所有的漢字?
如何區分一串字元是亂碼還是英文或是拼音?

TAG:遊戲 | 程序員 | 編程 | Unity遊戲引擎 |