1. 程式人生 > >Unity優化筆記——記憶體優化

Unity優化筆記——記憶體優化

Unity遊戲的記憶體主要劃分為Unity佔用、第三方庫佔用和系統層面的佔用三部分,而我們影響的最主要的是Unity層面的。

Unity層面主要分為資源、引擎native佔用和臨時物件三部分,我們分別從這三個部分分別進行優化。

  • 資源優化:

資源優化主要分八個模組進行:貼圖資源、模型資源、動畫資源、聲音資源、粒子特效、shader、指令碼、配置文字。其中貼圖、模型、動畫和聲音作為最常用的資源,主要的處理方式是有損資源壓縮(例如貼圖壓縮成ETC/PVRTC格式進行硬體加速;模型使用unity內建的壓縮排行,將臨近的頂點進行刪減;動畫將臨近的關鍵幀刪除;聲效壓縮成ogg格式等)。但是僅僅這樣是不夠的,而且會出現一些問題,比如安卓在OpenGL2.0上帶通道的貼圖沒辦法進行ETC格式的壓縮,IOS上壓縮成PVRTC格式後的質量也是不夠的。針對這些情況,可以將帶alpha通道的貼圖進行alpha拆分,拆分之後可以分別對RGB貼圖和alpha貼圖進行壓縮,這樣對於壓縮之後的貼圖的品質也會有一定的提高。

針對於動畫檔案,unity的動畫檔案往往會有一些冗餘的幀和冗餘的軌(比如在動畫中某些骨骼一直保持不動,這時候美術在動畫製作的過程中往往會將關鍵幀K滿,這樣往往會有一些直線的軌出現),這是關鍵幀中的一些冗餘資料是可以刪除的,我們通過解析Unity中的Animation檔案可以找到一些冗餘的關鍵幀,將它們刪除就可以了。

對於粒子系統,每一個粒子系統例項要佔到10K左右的記憶體,但是由於使用粒子系統在展現效果上比傳統的使用面片或動畫做出來的效果要好很多,因此美術更偏愛於使用粒子系統。但是從手機的效能考慮,要嚴格限制粒子系統的質量。

在使用shader尤其是從網上找到的shader時要注意裡面的一些坑,比如有些shader中包含了很多效果,但是我們需要用到的只有其中一個,還有就是shader中包含了很多預編譯的巨集。如果對每一個shader都進行編譯的話,這些沒有被使用的程式碼也會編譯成shaderProgram佔用額外的記憶體。

至於指令碼和配置問本,只需要注意及時解除安裝就好。

整體來說,資源優化最重要的一點就是做好LOD。

  • 引擎native佔用優化:

引擎佔用主要在AB層面的佔用和Mono堆的佔用。為了節省記憶體和熱更新,幾乎所有的手遊都會打AB,AB的載入策略和打包策略都會影響到對記憶體的佔用;而Mono堆更是對記憶體最主要的佔用之一。

AB包最主要的問題就是如何處理公共資源,在打包策略上通常有指令碼全自動打包和純手動打包兩種。

全自動打包可以通過程式自動處理資源的依賴關係,凡是公共的資源就打成公共的AB包。可是這樣公共的AB包就會非常多,為了減少載入時的IO要對公共的AB進行合包。一般一個ab包在10M以內比較合適。但是全自動打包的問題也是比較明顯的,在熱更新中哪些ab發生了怎樣的變化並不直觀,變向增加了管理成本。

純手動打包需要有明確的需求,並且要求邏輯分割明顯,比如Moba類的遊戲,可以將一個英雄的相關資源打在一起,這樣打出來的包更簡便,也不需要做合包這種事。這樣做的優點是邏輯清晰,明確知道哪些ab會發生變化,但是問題同樣很明顯:因為是手動打包所以後期需要人力成本維護,並且在專案前期需要及早的進入資源的規劃和管理中來。

因此在打包策略上需要根據專案的實際情況適當的將兩種打包策略結合使用。

AB的載入策略優化的主要方向是優化記憶體峰值,減少同時存在的資源路徑數量。因為AB檔案頭中儲存了這個AB中所有資源相關的路徑資訊,載入AB的時候這些資訊會載入到記憶體中來。資源路徑相關的資訊可以在Profiler中的PersistentManager和passname這兩項中看到。PersistenManager類似於mono堆的機制,峰值一堆上去就不會再釋放,所以對於峰值的優化尤為重要。主要方法是解析場景中需要載入的資源的依賴關係,將同樣依賴關係的資源儘量一起載入。這樣可以儘快解除安裝掉公共的AB包,確保同時存在的AB的數量是最小的。

Mono堆一般分為場常駐和瞬時分配兩種。常駐一般由於static變數和singleton單子發生的記憶體分配產生。這塊的分配非常細碎分散,處理不好可能會對專案的延展性產生較大的影響。這裡推薦使用騰訊的wetst工具進行分析,具體的分析和優化思路可以參考大佬的文章http://gad.qq.com/article/detail/20966。瞬時分配可以通過Profiler進行排查,並且平時要注意程式碼規範。

  • 場景中的臨時記憶體的優化:

臨時記憶體分為UI、Particle Instance、Batched Mesh三部分,UI會在背後產生一些不被察覺的mesh,所以要儘量減少UI的複雜度;特效在執行時複製很多份會導致大量的particle例項產生,此時要使用物件池規劃並減少particle例項的峰值;美術在使用合批工具時也會帶來合併mesh的記憶體消耗,所以需要合批的mesh需要美術線上下完成。

第三方庫在unity層面是無法監控和處理的,所以優化方法主要是延遲第三方庫的載入時間,用到了才去載入。並且注意做好模組分離,這樣可以在第三方庫記憶體佔用過大或者記憶體洩漏時使用模組隔離的方式快速確定是哪個庫出的問題。