FPS手游《战地先锋》性能案例精讲
一、CPU性能
該游戲在CPU占用方面的性能非常不錯,下圖為該游戲在紅米Note2 設備上按照劇情進行游戲時的性能數據。可以看出,在紅米Note2 上運行的24979幀中,超過33ms的幀數占比為4.3%,超過50ms的幀數占比為1.2%??紤]到切換場景時資源加載的開銷,一款游戲如果超過33ms的幀數占比低于10%,則說明該游戲在絕大多數時刻的運行中都是非常流暢的。
通過進一步統計,該游戲的CPU性能超過了84%的紅米Note2設備上的測試游戲,其能耗更是低于91%的同設備測試游戲。
其整體CPU性能的優秀表現與其各個模塊的合理使用是分不開的。下面,我們就詳細講解一下其CPU性能方面的亮點之處。
1、渲染模塊
通過UWA性能測評報告,我們可以看到該游戲詳盡的渲染模塊性能開銷。該游戲在紅米Note2設備上運行時的渲染模塊CPU開銷如下圖所示。通過統計,半透明物體渲染的CPU消耗均值為1.5 ms,主要集中在 0.7~2.7ms 范圍內(5%~95%)。不透明物體渲染的CPU消耗均值為1.8 ms,主要集中在 0.2~4.6ms范圍內(5%~95%)。
Draw Call峰值為340,雖然峰值較高,但僅在場景切換處出現,這是因為項目在動態加載后通過代碼調用StaticBatching的方式來合并Draw Call,所以可以看到Draw Call數量在進入場景后迅速回落。同時,Draw Call數量主要集中在 48~179 范圍內(5%~95%),屬于合理范圍之內。
下圖為該游戲在紅米Note2上的具體CPU性能堆棧??梢钥吹?#xff0c;該游戲在紅米Note2上無論是不透明開銷還是半透明開銷均處于較低水平,這得益于研發團隊對于場景模型、蒙皮網格和UI的控制十分得當。
美中不足的是Shader.SetPass稍高,這主要是渲染模塊中RenderState的切換較為頻繁所致,對此,建議大家對場景中的Material數量進行控制,具體可以參考:《使用MaterialPropertyBlock來替換Material屬性操作》
2、UI模塊
該游戲在紅米Note2設備上運行時的UI模塊CPU開銷如下圖所示。該游戲使用UGUI作為UI界面的解決方案。經過統計,UI模塊總體的CPU占用均值為1.9ms,主要集中在0.1~3.6ms范圍內(5%~95%),屬于合理范圍之內。
其均值高于70%的行業數據,這是因為該項目使用的是Unity 4.7版本進行開發,該Unity版本中,UGUI并沒有像Unity 5.3版本以后將部分拼合操作放到子線程中進行。在這一點上,Unity 4.x的UGUI性能較之5.3+版本確實要多一些性能上的開銷。堆內存平均每幀分配為5.5B,僅高于5%的行業項目,這說明該游戲UI界面的制作及UI重建的影響范圍非常合理。目前,UWA推薦UGUI模塊中,平均每幀堆內存分配盡可能控制在2KB以下。
從下圖中可以看出,Canvas.SendWillRenderCanvases在不同的運行時刻均出現CPU高值,但通過運行截圖可以看到,其共同特點是CPU耗時高值均發生在畫面底層的UI選人界面出現時。因此,該UI界面的出現或相關操作極有可能是引發Canvas.SendWillRenderCanvases CPU過高的原因,建議研發團隊對該界面進行進一步檢測。
3、動畫模塊
在UWA測評報告中,該游戲運行時的動畫模塊CPU開銷如下圖所示。
可以看出,除進入場景時出現CPU高值外,其在戰斗副本中的CPU開銷均控制在較低水平。Animator.Update的CPU均值為1.8ms,主要集中在0.1~3.4ms區間內,其性能較為優秀,高于28%的行業項目。同時,MeshSkinning.Update的CPU均值為1.8ms,主要集中在0.1~3.4ms區間內,高于21%的行業數據。
同時,經過進一步檢測發現,其進入副本時的CPU高值均為lhAnimatorEvent.OnEventCallback回調函數所致,具體的CPU耗時堆棧如下圖所示。通過此堆棧可知,其耗時主要為UI界面的加載耗時,且進一步通過資源管理信息可知其主要開銷為luaUI_PK(Clone)的Active操作和luaUI_Hall(Clone)的Deactive操作所致。因此,建議研發團隊可進一步檢測該UI的制作是否合理,并對其進行完善。
4、GC調用
該研發團隊對于GC調用頻率控制得非常出眾,游戲在運行過程中,GC調用頻率為1921幀/次,優于目前95%的行業內游戲。
一般來說,如果一款項目的GC調用頻率可以控制在1000幀/次以上,就已經相當出眾了。該游戲的GC調用頻率如此優秀,主要得益于研發團隊對于項目代碼堆內存的控制。下圖為游戲運行25000幀的代碼堆內存具體分配情況。對于使用UGUI的游戲來說,我們建議游戲運行每1萬幀中,Top10函數的堆內存分配總和小于30MB,而該游戲運行25000幀,其Top10函數的堆內存分配總和才26.91MB,足見該團隊對于堆內存分配的理解非常深刻。
二、內存模塊
《戰地先鋒》在內存上的表現如下圖所示??們却娣逯颠_到249MB,Mono堆內存峰值為32.5MB。243MB的總內存分配相對來說略高,研發團隊可嘗試在低端機器上對資源進行進一步控制,從而降低低端機器上的內存占用。
1、Mono堆內存
從上圖可知,該游戲的總體Mono堆內存控制得很好,在25000幀中,Mono的堆內存峰值僅為 32.5MB。該值屬于合理范圍之內(<40MB)。
但是,從走勢上來看,其堆內存的占用在游戲運行過程中持續處于上升趨勢,對此,建議研發團隊對緩存池進行進一步檢測,排查項目是否存在堆內存泄露的隱患。
2、資源內存
經過統計,該游戲的紋理資源數量峰值為618個,內存占用峰值119.5MB。紋理內存占用較高,目前高于82%的行業項目。經過統計,在內存占用峰值處,ETC1格式紋理占有221個,Alpha8格式紋理占有5個,RGBA32和ARGB32格式紋理共占有120個,RGB24格式紋理占有87個,其余為RGBA16格式紋理。
對于RGBA32、ARGB32的紋理,我們建議在視覺效果可以保證的情況下,盡可能使用ETC1格式紋理(Android平臺)進行替換,不僅可以達到更小的內存占用,同時可以獲得更快的加載效率。而對于無法進行硬件壓縮的紋理,可以通過Dither方法嘗試將其轉換成RGBA16格式的紋理,具體做法可以參考此篇文章。
其他資源的內存占用情況如下:
Mesh資源:
內存峰值高于41%的項目
AnimationClip資源:
內存峰值高于40%的項目
AudoClip資源:
內存峰值高于73%的項目
AudioClip的內存占用較高,高于73%的行業項目。對此,研發團隊可嘗試將內存占用較高的音頻資源通過Stream的方式來進行加載,該方式可極大降低AudioClip資源的內存占用。
以上則為《戰地先鋒》游戲在CPU性能和內存管理方面的具體使用情況。優秀的CPU性能、非常少的堆內存分配以及引擎模塊間的合理使用,足以看出該研發團隊非常深厚的技術功底和對于引擎相當優秀的把控能力。
三、性能優化、進無止境
該游戲在Shader加載和GameObject Active/Deactive方面仍有一定的提升空間。在此,我們對其進行羅列,希望同樣可以幫助到大家的研發項目。
1、Shader加載
目前,游戲副本切換時存在較高的Shader解析(Shader.Parse)開銷,如下圖所示。通過具體資源信息中的Shader資源分析,可以定位是如下幾個Shader的加載耗時,對此,建議研發團隊嘗試對頻繁使用的Shader進行預加載并常駐內存,從而減少不必要的Shader重復加載耗時。
2、GameObject Active/Deactive調用次數過高
該游戲在運行過程中,GameObject Active/Deactive的調用次數過高,在游戲運行的25000幀中,Active調用268952次,Deactive調用393490次。其調用的具體次數如下圖所示(下圖為游戲運行每10幀進行一次Sample,而每個Sample的數值為前10幀中Active/Deactive調用次數的總和。
其中,GameObject的Active/Deactive Top10資源信息具體如下所示,因此,研發團隊可通過下表直接對頻繁進行Active的GameObject進行完善。Deactive的完善亦然。
頻繁的Active/Deactive操作不僅會造成CPU的浪費,同時,它還很可能間接造成更大的CPU耗時,比如Animator.Initialize耗時。該游戲的Animator.Initialize調用較為頻繁,且耗時較高,如下圖所示,而這就是頻繁的Active/Deactive操作所造成的結果。因此,對于GameObject不必要的Active和Deactive操作進行控制,是非常有必要的。
最后,非常感謝《戰地先鋒》研發團隊對 UWA 的認可和支持。感謝他們樂于將項目性能數據與大家一起分享,讓更多的研發團隊了解到一款性能優秀的3D移動游戲在各個模塊上可以做到怎樣的程度。同時,也歡迎更多的開發團隊可以與我們一起來分享你們的性能數據,讓更多的游戲開發者受益!
PS:安利這款FPS手游,在TapTap上已經獲得了8.6的高分,并將于9月7日在14個安卓渠道同時開啟付費刪檔測試,歡迎大家來預約!
原文出處:侑虎科技
本文作者:admin
轉載請與作者聯系,同時請務必標明文章原始出處和原文鏈接及本聲明。
總結
以上是生活随笔為你收集整理的FPS手游《战地先锋》性能案例精讲的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图文具体解释 IntelliJ IDEA
- 下一篇: Go基础--goroutine和chan