【程序】Unity 性能 Review

年初的一次優化筆記,第一篇。每個版本一周,每個版本一篇已經6,7篇了。過早的優化可能並不是最好的,但是每個版本每個月都要上線測試。始終覺得對於實時多人競技遊戲來說,流暢的重要性超過畫面。

使用Unity的Profile先簡單分析

  • 角色更新過高,後面更詳細的分析。

  • 屏幕邊緣圖標和Wifi過高。優化方案:頻繁設置UI文字和貼了可以優化。

  • 放技能開銷非常高,每個子彈有獨立彈道邏輯,技能釋放頻率比價高。優化方案:類對象使用內存池,delegate優化減少gc,更完善的預載入機制,邏輯優化等等。CMT的timer使用內存池。

  • 部分非技能的CMT沒有預載入。

  • 召喚物沒有預載入。

  • 部分道具有些沒有預載入。

  • 消息處理非常卡。解決方案:使用類對象內存池,優化序列化方式不使用protobuff的。

  • 幀操作增減人會卡。解決方案:推測玩家行為預載入。

  • 飛行道具開銷很高,特別是Deactive上。解決方案:可見性使用layer,使用內存池

  • 地圖腳本開銷較高。

  • Camera.main直接調用開銷較高。解決方案:因為Unity會遍歷所有的Camera,是一個線性時間。在Update中調用的話,緩存一下main

    camera。

使用Unity的FrameDebugger簡單分析

  • 俯視角開啟了天空球渲染,其實沒必要

使用Unity MemoryProfiler分析內存佔用和內存泄漏

通過memoryprofile抓幀分析,內存佔用不高,但是RenderTexture佔用非常高63.5M

  • 大廳場景RenderTexture 63.5m。解決方案:因為使用了景深,擾動,屏幕校色,實時陰影,等後期處理效果所致,我們根據玩家手機配置做了自適應和限定,並且再圖形配置選項允許玩家做一些調整。景深開銷非常高因此關閉了實時景深效果使用其他方法代替。
  • 戰鬥場景Texture 33.7m Mesh 14.9m animationclip 3.7m Audiomanager 4.1M。解決方案:貼圖壓縮,使用shader減少換色貼圖,修正一些貼圖引用不釋放導致的內存泄漏。
  • LockstepMnanager.FixedUpdate函數 每幀分配10kb以上內存。解決方案:各種GC相關的優化。
  • SceneLoader.update函數(315 bytes) MainLoop.Update函數(202bytes), NetManager.update函數(186bs) CharacterActor.LateUpdate函數(392 bytes)皆為每幀都分配。GC的分配每幀超過200b就算大了。解決方案:各種內存優化,消息使用內存池等等。
  • MainLoop.OnGUI函數每幀分配內存 300b。解決方案:刪掉空函數。
  • 大廳場景Camera.Render cpu等待gnu渲染,造成時間幀率抖動 25ms-> 43ms 體現為Camera.Render self時間大幅變動 (優化方法 降低場景面數,拆分Gm_Cabin模型)
  • Loading貼圖存在偽內存泄漏,因為圖集和按鈕放在一起了被按鈕引用。
  • Unity技術支持提供了腳本插件可以分析代碼中所有靜態的引用。發現是lua的LuaScriptMgr中會對一些貼圖有引用,需要注意使用Lua導致的內存問題。

使用XCode做詳盡的性能優化

XCode也可以做GPU的性能分析。編譯xcode工程需要Development版,啟動,GUP的優化點需要在Run的面板里設置成metal否則有些堆棧看不到。點FPS,然後點相機Capture一幀,可以看到幀率,CPUGPU的佔比,渲染時每個函數的開銷。點Shader裡面的看更詳細堆棧,可以看到每個shader的每行代碼的開銷佔比。

  • 這個版本大廳很簡單但是非常非常卡,看到UI和景深開銷佔比比較高,UI佔了25,景深佔了30。看到UI費是採樣一張貼圖佔了50但是這張貼圖並不大,景深費是因為shader里lerp了很多次導致開銷很高。在FrameDebugger里可以看到UI最後渲染了一個全屏的面,可以看到每次渲染了佔用的時間比,這個面實際沒用。關閉了這個UI的全屏面,關了景深和後處理,基本就沒開銷了,連UI的渲染也只有2ms了因為景深把匯流排帶寬給佔滿了,其中最費的還是景深效果。

渲染線程開銷也較高

  • 版本機出的版本在XCode中會報錯APPLE MACH-O Linker Error,無法做性能分析。解決方法:改成il2cpp了。
  • 修復字元串拼接的量級,使用StringBuilder等。
  • OnGUI,FixedUpdate,Update等空函數也會有gc開銷,因為會產生從C++到C#層調用的開銷。最好都去掉。
  • FMOD音效模塊開銷過高。我們沒使用官方的FMOD使用了FMODStudio,測試版資源為了效果和開發方便使用了一些事件內的效果器。優化後音效佔用10-15%。

  • 動畫開銷較高,使用了動作融合,動畫狀態機較複雜。解決方案:不可見的角色不更新動畫,一些頂點受骨骼影響數可以設置很小,小怪等簡單角色使用Animation,動畫的一些優化等。

  • UI,粒子,動作開銷較高,並且多線程開銷也高。

  • 可以看到每個模塊開銷比較平均,已經做了很多優化了沒有明顯瓶頸,只能一個模塊一個模塊的摳了

其他一些測試以及和Unity官方支持的問答:

  • Unity的物理比射線省,因為會優化做空間劃分,只計算較小範圍。Navmesh最優化。
  • 迷霧和可以性檢測可見性預緩存,預緩存分塊載入,迷霧進行分塊劃分優化,分擔計算量到多幀執行等等
  • Resource目錄資源多會導致Unity進遊戲時間特別長,因為會把Resource下所有資源做一次檢索,導致啟動慢。建議使用Assertbundle,也支持壓縮。另外提升進入遊戲速度的就是,第一個場景足夠簡單足夠小。解決方案:開發了熱更的資源管理,每個資源有一個唯一ID,可以存在Resource下也可以存在Assertbundle中。
  • Assetbundle的新演算法是按Chunk載入,不會把整個Assertbundle都載入進來但是壓縮比小,壓縮的時候要選擇ChunkBase。如果bundle載入好之後資源的引用時放在bundle上,如果a界面打開bundle包讀取貼圖,a界面關閉則貼圖會釋放,如果a沒關閉,b界面讀取貼圖b界面會對應到同一張貼圖上。
  • 建議bundle放在StreamingAssets目錄下。
  • Profile分析建議:Overhead,是Unity沒統計到的時間,用總計時間減去剩餘的時間,一般包括C++到C#層的調用開銷,場景複雜度,垂直同步等。大廳因為Overhead卡是因為CPU在等GPU,建議用XCode看。
  • 通過Profile.BeginSample自己插代碼對懷疑的代碼進行內存和性能調試。
  • Unity5.3.5p8修改了Foreach裝箱拆箱導致的內存開銷。但是沒有修改mono的gc。實際測試可以用Foreach了。
  • 部分Android設備匯流排太爛導致GC會特別卡
  • OnGUI,FixedUpdate,Update等空函數也會有gc開銷,因為會產生從C++到C#層調用的開銷。最好都去掉
  • 部分3G的Android設備,實際可用內存可能只有500M。Unity啟動時最高能佔到80M,一般在40-50M
  • unload切場景自動調,gc也會自動調
  • 編輯器下看到的資源引用計數不準確,得看真機。實際測試的時候老發現很多資源釋放不掉,但是到真機測試發現實際已經釋放掉了,因為編輯器模式會緩存一些資源,所有的測試都應該以真機為準。
  • lua導致gc太多,沒有比較好的解決辦法,把lua的代碼放到C# 層
  • IOS上如果限45幀對IOS來說就是限30幀,低於30幀才是真實幀率
  • CPU優化:ulua的計時器開銷很大。其中PreloadManager是Unity的各個模塊的預載入。
  • GPU優化:Mask會很費。

推薦閱讀:

UWA 兩周年 | 優化就是在和時間賽跑
你知道這款數據驅動優化的利器嗎?
優化演算法之梯度下降演算法
小型 Web 頁項目打包優化方案

TAG:优化 | Unity游戏引擎 |