騰訊大咖說:騰訊是如何做Unity手遊性能優化的

原文鏈接:https://blog.csdn.net/wetest_tencent/article/details/51784782

本文由騰訊WeTest授權發佈 
作者:chunhe,騰訊資深後臺開發工程師。 
鏈接:http://wetest.qq.com/lab/view/108.html 
著作權歸作者所有。商業轉載請聯繫WeTest獲得授權,非商業轉載請註明出處。

俗話說,用戶體驗不談性能就是耍流氓。 在PC遊戲上的性能問題並沒有那麼明顯,加個內存換個CPU或者刷個主頻就能輕鬆搞定;到了手遊時代後情況則顯得比較嚴峻,捉襟見肘的內存使得資源加載時如履薄冰,加上高中低不同配置的機型讓性能問題顯得更加突出,一個低端機型上的卡頓就可能造成一大批屌絲用戶的流失,這當然無法被忽視。

在手遊的浪潮之巔,騰訊對於手遊品質的要求從1.0到2.0再到現在的3.0,不僅是玩法和內容,在遊戲質量的審覈上也始終如一的保持着高要求高標準。騰訊遊戲的品質管理中心在Unity手遊性能上進行了更深層次的挖掘,這是一個騰訊內部非常受歡迎的性能分析產品,無論你是否正在從事Unity相關的工作,聽完這個良心產品的故事保證會讓你增加90%的魅力值。但在此之前、先要看看你的“性”能到底行不行?

(下文有大量專業術語,有可能引起您的不適,請在家長指導下閱讀。)

一.常見的Unity手遊性能問題有哪些?

Unity手遊的性能問題一直是被業內視爲詬病,騰訊公司內部的TDR評審就是一個專門針對技術細節進行專家團評估的環節;早期的TDR評審關注的是內存是否超標、CPU是否飽和、網絡流量是否過大等數據,經過近幾年手遊浪潮的洗禮,現在評審過程中會更加註重細分問題的研究和排查。 


如果說左邊是玩家經常會遭遇到的表面現象,那右邊則是基於Unity引擎深挖後的問題本質。 它們對遊戲的具體影響是什麼呢?就拿最近比較火的《王者榮耀》來舉例,我們有幸參與了它上線前後的幾個優化版本的分析,先後遇到過的問題和優化方法主要有下面幾個: 


1.由於實時對戰遊戲的數據包數量巨大,早期版本的幀同步策略會導致比較明顯的卡頓,通過進行數據包的合併與優化逐漸解決了卡頓問題; 
2.頻繁創建和銷燬的小兵對象讓CPU爆表了,大量的小兵如果採用實時內存的分配和回收,會產生大量的內存碎片和系統開銷,解決方法之一就是採用高效的對象池進行優化,對每個內存對象的狀態進行操作即可; 
3.性能分析過程中,發現單人同屏和多人同屏時的開銷都很大,通過視野裁剪技術,使得玩家視野外的不必要的特效和渲染可以全部關閉,極大降低了CPU、GPU和內存的開銷; 
4.在高中低三檔機型上玩遊戲時,分別加載不同層次的特效包,這也有助於降低CPU和內存的開銷; 
5.遊戲內界面採用了UGUI的方式實現,但大量的實時UI變化使得副本內每幀會有230以上的drawcall,導致中低端機型感受到明顯卡頓,最終採用UGUI+自研究UI的組合拳,重寫了一套緊密結合遊戲自身特性的UI來實現戰鬥血條和浮動文字的效果。

二.手遊發佈之前的性能分析

近年來,經過若干慘痛的教訓之後,業內已經逐漸意識到手遊性能已成爲了生死存亡的關鍵,特別是對於做大DAU的手游來說尤爲重要。騰訊對於手遊性能的測試和監控也是多管齊下,在新版本發佈之前會再三確認性能是否符合發佈標準,拿王者榮耀這款實時競技遊戲來說,在測試階段會採集大量的性能數據進行分析,測試經理對各項性能指標進行評估並給出最終質量結論。 


如上圖所示,首先,功能測試也就是通常所說的人肉測試,用於測試遊戲的新、老功能點,測試工程師在工作過程中可以使用Cube進行數據採集;自動化測試則是基於騰訊WeTestgautomator自動化框架來實現,功能類似於Robotium,在無須人力參與的情況下能覆蓋到絕大部分技能、角色和關卡;灰度發佈指的是在一個很小範圍定點推送手遊的新版本,並觀察運營期的質量情況和玩家反饋。無論是哪種測試方法,在過程中都可以用Cube進行數據採集,在測試完成後,服務器會自動進行數據分析並給出多項性能數據結論;這些性能數據的結論來自於Unity官方的推薦標準值和騰訊遊戲海量的經驗庫,如果同意機器給出的結論則可以鞏固當前算法,當然也可以挑戰自動分析的結論,幫助後臺改進算法,最終版本質量結論還是來自於測試經理的判斷。

看到這裏是不是有一個疑問:不做性能分析行不行?當然行,並且你的產品照樣能發佈、能上線,帶來的結果就是用戶抱怨用戶投訴用戶流失。生病了、還得老老實實的去看病去吃藥;冰凍三尺非一日之寒,一場大病的費用遠比日常保養要貴的多,對應測試行業的名言就是“bug發現的越早、修復成本越小”。

三.Cube工具的簡介

目前市面上大多數性能工具都還停留在操作系統級別的數據上, 在遊戲自身的分析上似乎還缺少點什麼,所以騰訊的工程師們覺得還可以往靈魂深處挖一挖,於是就研發了Cube這個手遊性能分析工具,可以讓用戶以最小的成本在真機上進行遊戲性能深度分析。常見的遊戲質量改進的過程如下圖,Cube能幫你完成的是前兩個環節,至於第三步、解決問題當然還是要開發人員去改代碼了。 


通過Cube的深度分析,能夠幫助開發者發現當前遊戲內分類資源的佔用情況。 


如上圖所示,在資源分析緯度上可以給出如下結論:

· 資源使用總量是否在合理範圍之內。

· 一個場景內的資源重複率。

· 資源對象拷貝的數量是否合理。

· 場景切換時保留的資源詳情。

· 網格、紋理、音頻、動畫、GameObject等資源是否超標。

在性能分析緯度上,以騰訊的TDR標準爲例,在高中低三檔機型上會有不同的標準,Cube在三檔機型中做了自動的篩選和判定,便於開發人員能更加直觀的發現問題。(如下圖) 


首先、在遊戲場景內對於FPS、CPU、PSS的變化趨勢是需要重點關注的;其次、對於mono這種只增不減的東西,當然也是關注的重點,mono堆內存的不斷分配會直接導致PSS內存增長且不可逆;再次、對於和渲染有關的drawcall,也是手遊需要關注的性能指標之一,drawcall太高會導致FPS陡降,造成視覺上的卡頓。

四.同類工具對比

MAT (Memory Analyzer Tool)的缺點:

l 需要導入HPROF文件再分析;

l 只能查看java層的內存情況,看不到native堆的詳情;

xcodeinstrument 的缺點:

l 只能用於mac,ios;

l 只能查看C++ 或 object C 的情況,看不到mono堆的詳情;

Unity Profiler 的缺點:

l 需要單獨編譯develop版本;

l 在PC上執行,沒法捕獲真機數據;

l 內存數據跟實際真機的數據差異很大、多的時候有幾十M差距;

l 只能看到最近一段時間的數據,看不到總體的詳情;

對於Unity大神和開發人員,你更關心的應該是詳細的性能數據,都能滿足你們。大神會說“我更喜歡看着Unity profiler直接調試啊”,那你還得騰出時間編譯一個develop版本、還得重新跑一遍遊戲、數據和真機還相差很多,關鍵是大神哪來那麼多時間呢? 


所以答案是肯定的,日常測試工作中加入了數據採集和數據分析功能,就可以提高很大的工作效率。

我們常見的產品質量改進流程無非是下面這四步:

1) 測試人員發現問題;

2) 提bug 給開發人員;

3) 開發人員編譯develop版本;

4) 開發人員用Unity profiler 定位原因;

用Cube進行遊戲測試能幫你省掉後面2個步驟,何樂而不爲呢?

通常情況下,開發人員是間隔幾個星期甚至幾個月纔會去做一次性能調優的工作,中間已經隔了N個版本,有很多問題會被埋的很深;基於“問題發現的越早修復成本越小”的硬道理,功能測試人員完全可以用Cube進行日常的版本功能測試,讓Cube在後臺默默的爲你發現各種性能問題。

l 即插即用、無須編譯無須嵌入SDK、真機運行數據;

l 提供mono內存分配信息和mono快照對比;

l 能看到整個測試流程中的所有數據,而不僅僅是某一段時間;

l 被誤操作產生的對象拷貝數量;

l 函數開銷排名;

l 關卡間保留的冗餘資源;

五.性能優化的N種武器

作爲一個以性能優化爲己任的工具類產品,Cube不僅致力於問題的發現和定位,也希望爲開發人員提供更多更實用的性能優化方法。

貼圖:

l 控制貼圖大小,儘量不要超過 1024 x1024;

l 儘量使用2的n次冪大小的貼圖,否則GfxDriver裏會有2份貼圖;

l 儘量使用壓縮格式減小貼圖大小;

l 若干種貼圖合併技術;

l 去除多餘的alpha通道;

l 不同設備使用不同的紋理貼圖,分層顯示;

模型:

l 儘量控制模型的面數,小於1500會比較合適;

l 不同設備使用不同的模型面數;

l 儘量保持在30根骨骼內;

l 一個網格不要超過3個material;

動畫:

l N種動畫壓縮方法;

l 儘量減少骨骼數量;

聲音:

l 採用壓縮MP3 和 wav;

資源方面的優化:

l 使用 Resource.Load 方法在需要的時候再讀取資源;

l 各種資源在使用完成後,儘快用Resource.UnloadAsset和UnloadUnusedAsset卸載掉;

l 靈活運用AssetBundle的Load和Unload方法動態加載資源,避免主要場景內的初始化內存佔用過高;(實現起來真的很難…)

l 採用www加載了AssetBundle後,要用www.Dispose 及時釋放;

l 在關卡內謹慎使用DontDestroyOnLoad,被標註的資源會常駐內存;

代碼的優化:

l 儘量避免代碼中的任何字符串連接,因爲這會給GC帶來太多垃圾;

l 用簡單的“for”循環代替“foreach”循環;

l 爲所有遊戲內的動態物體使用內存對象池,可以減少系統開銷和內存碎片,複用對象實例,構建自己的內存管理模式,減少Instantiate和Destory;

l 儘量不使用LINQ命令,因爲它們一般會分配中間緩器,而這很容易生成垃圾內存;

l 將引用本地緩存到元件中會減少每次在一個遊戲對象中使用 “GetComponent” 獲取一個元件引用的需求;

l 減少角色控制器移動命令的調用。移動角色控制器會同步發生,每次調用都會耗損較大的性能;

l 最小化碰撞檢測請求(例如ray casts和sphere checks),儘量從每次檢查中獲得更多信息;

l AI邏輯通常會生成大量物理查詢,建議讓AI更新循環設置低於圖像更新循環,以減少CPU負荷;

l 要儘量減少Unity回調函數,哪怕是空函數也不要留着;(例如空的Update、FixedUpdate函數)

l 儘量少使用FindObjectsOfType函數,這個函數非常慢,儘量少用且一定不要在Update裏調用;

l 千萬一定要控制mono堆內存的大小;

六.小結

性能優化就像海綿中的水,又或是內衣裏的肉,擠一擠總會有的。同時,性能優化並不是一勞永逸的工作,而是一個漫長而具有挑戰的任務;項目的各個階段都會有性能上的問題,在用戶體驗的基礎上持續進行打磨,持續保持產品的良好性能才能贏得好口碑。(和保持身體健康是一個道理) 


Unity手遊的性能優化過程更像是一門時空轉換的藝術, 持續在CPU和內存之間取得一個平衡。空間不足時則需要釋放一些無用數據,以獲得更優的空間使用率;時間太長時就需要降低不必要的函數開銷。例如在低端機上,爲了節約有限的內存空間,靜態加載的資源會相對較少,很大一部分資源通過動態加載和釋放;而在高端機上則不用考慮空間的限制,可以一次性靜態加載更多的資源,省去了不少loading和GC的工作,讓遊戲體驗更加流暢。 UnityCube目前已經可以使用。

體驗地址:http://wetest.qq.com/cube

關於測試報告的問題:http://wetest.qq.com/guide/view/?id=267

使用幫助:http://wetest.qq.com/guide/view/?id=266

常見問題:http://wetest.qq.com/guide/view/?id=268
--------------------- 
作者:騰訊WeTest 
來源:CSDN 
原文:https://blog.csdn.net/wetest_tencent/article/details/51784782 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章