今天我們為大家帶來由福州朱雀網絡研發的MOBA手游《小米超神》的UWA測評報告分析。該游戲在不同配置的移動終端設備上,無論是畫面表現力,還是性能開銷都非常優異。在此,我們將對該款游戲的性能數據進行深度剖析,希望通過這篇文章可以讓大家對移動游戲各個模塊的運行效率有更為深刻的認知,并對大家的項目研發有所幫助。
一、CPU性能
該游戲在CPU占用方面的性能非常不錯,下圖為該游戲在紅米Note2設備上進行一場5V5戰斗時的性能數據。
可以看出,在紅米Note2上運行的19876幀中,超過33ms的幀數占比為13.9%,超過50ms的幀數占比為1.7%,并且從圖中可以看出,其CPU耗時較高處主要集中在5V5場景的資源加載階段。因此,該游戲在戰斗時的性能可以說是非常優秀,絕大多數時刻游戲運行非常流暢。
同時,通過進一步統計,該游戲的CPU性能超過了64%的同設備(紅米Note2)上測試的其他游戲,其能耗更是低于86%的同設備測試游戲。由于目前國內的MOBA游戲較少,所以上述排名并不是在MOBA類型中的排名,而是在所有類型游戲中的排名。對于一款超重度的MOBA移動游戲來說,該CPU性能和能耗排名可以說是相當出色。
其整體CPU性能的優秀表現與其各個模塊的合理使用是分不開的。下面,我們就詳細講解其CPU性能方面的亮點之處。
1、渲染模塊
通過UWA性能測評報告,我們可以看到該游戲詳盡的渲染模塊性能開銷。該游戲在紅米Note2設備上運行時的渲染模塊CPU開銷如下圖所示。通過統計,半透明物體渲染的CPU消耗均值為1.7 ms,主要集中在0.8~3.0 ms范圍內(5%~95%)。不透明物體渲染的CPU消耗均值為1.0 ms,主要集中在0.2~1.7 ms范圍內(5%~95%)。可以看出,在整個5V5戰斗過程中,無論是移動、Farm、Gank還是團戰,甚至上高地時,其渲染耗時都穩定在一個較低的耗時區間。這得益于研發團隊對于場景模型、蒙皮網格和UI的控制十分得當。
Draw Call峰值為167,且主要集中在 45~130范圍內(5%~95%),渲染三角形面片單幀峰值為64900,以上數值均處于合理范圍之內。
2、UI模塊
該游戲在紅米Note2設備上運行時的UI模塊CPU開銷如下圖所示。該游戲使用UGUI作為UI界面的解決方案。經過統計,UI模塊總體的CPU占用均值為1.5 ms,主要集中在0.1~3.5 ms(5%~95%),屬于合理范圍之內。堆內存累積分配為16000幀 2.4MB,平均每幀分配堆內存155.4B,這說明該游戲UI界面的制作及UI重建的影響范圍非常合理。目前,UWA推薦UGUI模塊中,平均每幀堆內存分配盡可能控制在200B以下。
戰斗場景中,UI系統的性能耗時主要是由UI元素的狀態變化而導致的,比如血條、飄字等HUD的移動、消隱等。這種操作稍不注意,就會帶來較高的UI網格重建開銷。所以,UI界面的研發看似直觀、簡單,但是其對于制作時的層層考究和運行時的耐心調優,則是一款產品是否“匠心”的試金石。以下則為《小米超神》這款產品在經過幾輪優化后的UI性能對比圖。
3、動畫模塊
在UWA測評報告中,該游戲運行時的動畫模塊CPU開銷如下圖所示。可以看出,除進入場景時出現CPU高值外,其在戰斗副本中的CPU開銷均控制在較低水平。Animator.Update的CPU均值為2.0 ms,主要集中在0.1~4.3ms區間內,對于MOBA項目5V5場景來說,基本上每幀均有90-130個物體在進行運動(除英雄、小兵之外,還有信使寵物、野怪、塔、插眼等等),由于玩家可以隨意查看地圖上任何一個角落的特點,其每幀的動畫系統壓力要比常規的MMO游戲大上數倍。因此,《小米超神》可以將其控制在均值2.0ms的水平線上,已經是非常優秀的數據了。
同時,經過進一步檢測發現,動畫模塊的耗時主要由Animators.ProcessAnimationsJob和Animators.FireAnimationEventsAndBehaviours導致,前者主要是持續的累積耗時,而后者則是非連續的“尖刺”開銷。前者是動畫系統對于AnimationClip的讀取和計算耗時所致,其耗時大小與當前幀參與計算的骨骼節點數、動畫曲線數、動畫執行狀態和Animator Controller的具體設置相關,其具體說明可參見《Unity中動畫系統性能優化方案回顧》;后者則是動畫事件的具體耗時,主要是項目邏輯代碼的性能開銷,此處研發團隊可以通過性能堆棧來進一步查看其邏輯代碼的開銷是否有進一步的優化空間。
4、GC 調用
該研發團隊對于GC調用頻率控制得非常出眾,游戲在運行過程中,GC調用頻率為1656幀/次,優于目前93%的行業內游戲。一般來說,我們建議一款項目的GC調用頻率可以控制在1000幀/次以上。
該游戲的GC調用頻率如此優秀,主要得益于研發團隊對于項目代碼堆內存的控制。下圖為游戲運行20000幀的代碼堆內存具體分配情況,其Top10函數的堆內存分配總和不超過80MB,足見該團隊對于堆內存分配的理解非常深刻。
當前版本的堆內存分配仍然有進一步下降的空間,從堆棧信息中可以看到,其Log輸出仍然存在一定堆內存分配,建議研發團隊在Release版本中將非關鍵性Log進行屏蔽。
二、內存模塊
《小米超神》在內存上的表現如下圖所示。總內存峰值達到297MB,Mono堆內存峰值為48.9MB。297MB的總內存分配相對來說略高,研發團隊可嘗試在低內存機器上對資源進行進一步控制,從而降低低內存機器上的內存占用。
1、Mono堆內存
從下圖可知,該游戲的總體Mono堆內存控制得很好,在20000幀中,Mono的堆內存峰值為48.9MB,該值略高(UWA建議《40MB)。從圖中看,是戰斗最后上高地時突然出現了較高的堆內存分配,迫使Mono堆內存上漲了8MB(如下圖紅框所示),對此,研發團隊可以根據具體位置查看其堆內存分配,即可定位其具體的堆內存分配根源。
但是,從走勢上來看,其Used Mono堆內存占用在5V5戰斗結束后,并未完全回落到場景之前(如藍框所示),這一點需要引起研發團隊注意,確認其是否為部分指定容器緩存所致,從而排查項目是否存在堆內存泄露的隱患。
2、資源內存
經過統計,該游戲運行時的紋理資源數量峰值為1003個,內存占用峰值54.8MB。研發團隊將紋理內存占用控制得很低,目前僅高于30%的行業項目。經過統計,在內存占用峰值處,ETC1和ETC2格式紋理占有835個,RGBA32格式紋理共占有89個,RGB24格式紋理占有5個,其余為RGBA16格式紋理。
紋理資源在項目運行期間的總體使用情況:
對于紋理資源的優化,一般可分為以下幾種:
(1)使用更合適的紋理格式
從上圖中可以看到,在整個游戲一場5V5戰斗過程中,RGBA32格式紋理的使用數量較多,其使用總量已經超過了91%的的行業項目。對此,我們建議在視覺效果可以保證的情況下,盡可能使用ETC1格式紋理(Android平臺)進行替換,不僅可以達到更小的內存占用,同時可以獲得更快的加載效率。而對于無法進行硬件壓縮的紋理,可以通過Dither方法嘗試將其轉換成RGBA16格式的紋理,具體做法可以參考Unity圖片優化神器 - Dither算法進階方案。
(2)使用更精準的紋理分辨率
一般來說,為了讓模型看上去更加精美,除Mesh模型本身以外,其對應的紋理都會選用較高的紋理尺寸,從而讓其看上去更加精致。但是,由于渲染物體在真正的游戲中相對于相機是有遠近之分的,其顯卡底層往往沒有(或根本不需要)使用如此高的分辨率來進行渲染,從而就造成了大量的資源浪費,這在我們深度優化過的項目中比比皆是。因此,我們建議可以通過UWA線上測評報告中GPU性能的Mipmap功能頁面來直接查看游戲運行時,其底層的紋理分辨率使用情況,如下圖所示。
同時,在深度優化報告中,我們也會進行更大量的測試和幾十億像素累積分析,從而來精準指出到底哪些紋理資源的分辨率制作過高,可在不影響視覺效果的前提下,將其分辨率縮小4倍、16倍甚至更多。《小米超神》項目通過這種方式不斷優化,其5V5場景的紋理內存已經從之前的78MB降到了現在的52MB。
以上是紋理資源的使用情況,其他資源的內存占用情況如下:
網格資源在項目運行期間的總體使用情況:
Mesh資源的內存占用較高,高于60%的行業項目。對于Mesh資源內存的優化,主要有以下幾種方法:
(1)控制網格頂點屬性的使用
詳細檢測網格模型中的Color數據和Tangent數據,當不需要時切記要將其進行去除,否則會在場景模型拼合時產生大量的內存浪費,具體詳細說明可以參考《移動游戲加載性能和內存管理全解析》。
(2)控制網格頂點的數量
詳細檢測網格模型的頂點數(或面片數)使用是否過大。這是一個說起來容易但實施起來很難的問題,其難點在于如何定義一個Mesh網格的頂點數是否過大。在UWA測評報告中會有一個建議,即建議將Mesh網格頂點數控制在1500個以下。但實際上,這其實是一個“不科學”的規定,因為沒有任何一個理論可以證明,其網格數量大于1500就是不合格,或則小于1500就一定合格。所以,我們這一年來花了大量的時間來尋求一種更為合理、科學的判斷規則。我們認為判斷一個網格模型使用是否合規并不應該是“靜態”檢測,而應該是一種“動態”檢測,與上述紋理資源的檢測一樣,我們應該去看網格資源在底層渲染時到底占據了多少像素,從而以一種密度統計的方式來判斷其網格使用量是否合理。因此,我們提出了一種網格模型測量標準,即“網格模型渲染密度”,其表示每單位數量(比如,1萬)像素中,其網格模型的渲染頂點數量。
下圖則為游戲運行過程中的網格模型渲染密度統計值。可以看出,雖然第一個模型“Mod_xyc_fz1001”的頂點數僅為1168,但其在游戲運行時平均每幀的渲染像素量僅為34.91個,也就是說平均每個像素要渲染33個網格頂點,這顯然是一種浪費。因此,通過“渲染密度”這一檢測方式,可以反映任何一個模型在游戲運行時的使用情況。在我們來看,這是一個比單純設定1500更加合理的判斷規則。
AnimationClip資源在項目運行期間的總體使用情況:
AnimationClip的內存占用較高,高于76%的全類型游戲項目。對于一款MOBA項目來說,其內存占用較高是可以理解的,因為其戰斗副本中擁有大量的動畫模型,比如英雄、小兵、野怪、塔、基地等建筑等等。對此,僅能建議研發團隊嘗試從數量上進行進一步地縮減,以降低其內存的使用。同時,對于動畫片段內存的一般優化還有“縮減精度”、“使用Humanoid類型”等方法,其具體優化方法可以參考《Unity中動畫系統性能優化方案回顧》。
三、資源管理
該游戲在資源實例化/銷毀、Active/Deactive等方面做的非常出色!在游戲運行的20000幀中,Instantiate和Destroy調用次數分別為1653次和4019次,而Active和Deactive調用次數則分別為116次和1447次。同時,對于Instantiate和Destroy操作來說,其主要調用均在進出戰斗場景處,副本中雖有Instantiate調用,但無論是頻率還是CPU耗時,均處于合理范圍之內,如下圖所示。
對于GameObject相關的資源管理,我們的建議如下:
(1)對項目中存在頻繁Instantiate/Destroy操作的GameObject一定要進行大力徹查,下圖即為某一項目的Instantiate實例化詳情,我們建議對于紅框處高頻率和耗時的操作重點排查,因為其無論是CPU還是堆內存都對項目性能造成非常大的殺傷力!
(2)頻繁的Active/Deactive操作不僅會造成CPU的浪費,同時,它還很可能間接造成更大的CPU耗時,比如Animator.Initialize耗時。在此,我們不妨看下另一款游戲的Animator.Initialize調用情況,如下圖所示,其調用的頻率和耗時較高,這就是頻繁的Active/Deactive操作所造成的結果。因此,對于GameObject不必要的Active和Deactive操作進行控制,是非常有必要的。更為詳細的資源加載性能優化總結,可參見《Unity移動游戲加載性能和內存管理全解析》。
(3)不斷檢測、不斷完善,優化是一個需要不斷迭代、持之以恒的事情。下圖則為《小米超神》經過幾輪優化之后的資源管理變化情況。
以上則為《小米超神》游戲在CPU性能和內存管理方面的具體使用情況。優秀的CPU性能、非常少的堆內存分配以及引擎模塊間的合理使用,足以看出該研發團隊非常深厚的技術功底和對于引擎相當優秀的把控能力。
最后,非常感謝《小米超神》研發團隊對 UWA 的認可和支持。感謝他們樂意將項目性能數據與大家一起分享,讓更多的研發團隊了解到一款性能優秀的MOBA手游在各個模塊上應該做到怎樣的程度。同時,也希望更多的開發團隊可以與我們一起來分享他們的性能數據,讓更多的游戲開發者受益!
關于UWA
由侑虎科技開發的游戲/VR應用性能優化平臺,目前提供 三大工具,幫助開發者在短時間內大幅度提升性能表現;同時其搭建的知識分享的博客(blog.uwa4d.com)和答疑解惑的互動平臺(answer.uwa4d.com)使廣大開發者收益,UWA以實力和態度詮釋對性能優化的定義:問題的答案永遠“在現場”,解決你的性能問題,才叫“優化”。
評論