Unity中國區技術支援總監:我們是如何做效能優化的?
在今天舉辦的Unite2017開發者大會上,Unity大中華區技術支援總監張黎明以“Unity企業級支援案例與分析”為主題進行了分享。
以下為演講實錄:
張黎明:非常感謝大家來參加今年的Unite,其實我現在看到有的朋友已經不是第一次來參加Unite,我是第三次站在Unite講臺上面,感到非常榮幸。
今天的題目是Unity企業級支援案例與分析,我們Unity在中國的業務已經開展五年時間了,最近一兩年時間發展非常快,國內現在規模上排名靠前的遊戲開發公司基本上都是我們Unity企業支援服務的客戶,最近這一兩年,遊戲市場也發生了一些變化,現在的廠商已經逐漸都往重度的遊戲轉型,不像過去兩年前,很多公司還是在做休閒遊戲,現在幾乎我們能見到大部分企業客戶都做重度遊戲。
開發者都在想盡辦法挖掘手機硬體的潛力,在這個過程中,我們也是和企業客戶發現了很多問題,在這裡希望和大家把這些問題分享出來。
我今天首先介紹一下Unity企業支援服務介紹,後面會講一下我們在企業支援的過程當中,我們大部分的客戶都比較關心的一些話題,最關心的就是效能分析,因為遊戲開發具體技術來講,因為每個專案遊戲型別不一樣,使用的技術也有可能有很大的差別,不同的專案可能不會有很多共同的話題,但是效能是所有專案都非常關心的。
後面也是大家都比較關心的,就是說我怎麼樣選一個引擎版本,遇到Bug、遇到崩潰會怎麼處理等等一些常見問題。
然後簡單的介紹一下我們企業的內容,我們有線上支援、效能優化,我們每個月定期進行線上優化,解決一些疑難雜症,可能有一些特殊的Bug處理,對我們企業客戶的Bug有特殊的處理流程。
還是進入主題,就是我們所有開發者關心的效能優化的問題。效能優化這方面,我們官方的技術支援團隊,現在是希望在這三個方面給大家有所幫助。
首先,我們給企業客戶提供Project Review服務,到線上做兩天的效能優化和效能分析,給出一些意見。下面我們分享我們在分析的過程當中,很多專案都遇到的一些效能問題,我把它總結了一下,然後後邊介紹我們做效能分析的時候常見的效能工具,對大家分析效能比較有幫助,最後介紹現在中國技術團隊在開發的一個線上效能分析的平臺,也是簡單的介紹一下。
下面介紹一下Project Review常見問題,首先我們一般開始檢查這個專案的資源管理這方面的設定,大家知道要檢查一下資源匯入有沒有問題,這裡我總結了一下,其實我們很多專案在資源匯入方面都會遇到一些問題。
首先,是一個我們做這個模型匯入要使用FBX檔案,我們見到很多專案它的模型匯入會把Read/Write Enable開啟,這裡強調一下,這個設定開啟一下會導致記憶體翻倍。
模型匯入有三個選項卡,其中一個是動畫相關的選項卡,我們預設不是None,即使FBX裡面沒有動畫資料的話,也會預設新增一個Animator的元件,會增加了記憶體的佔用,建議大家檢查一下匯入設定。
對於音訊設定方面,我們建議iOS使用mp3,安卓採用vorbis。動畫方面我們遇到很多專案動畫資源佔用過多的記憶體,一方面我們可以設定動畫的壓縮,其實可能很多開發者都知道,除了動畫壓縮之外,還有一個方式就是你要檢查一下原始動畫製作的時候是按照什麼幀率製作出來的。
然後還有音訊的一個採用率,一般採用率20k就夠了。音訊檔案還要考慮是單聲道還是雙聲道,一般情況下用單聲道效果是足夠的,我們把它壓縮成單聲道也可以減少記憶體的佔用。
然後對音訊的載入情況,我們建議對這些小的音訊檔案採用Decompress On Load這種模式,因為對小的音訊檔案的話,你在載入的時候解壓縮一次,這樣播放的時候不需要重新解壓縮,如果每次解壓縮會導致手機發燙、續航減少等等問題。
還有經常遇到的問題,我們FBX匯入的時候,如果不使用一些Normalmap等特性,你如果開了Normal Tangent匯入也都是浪費了記憶體空間,我們一般都是在專案開始初期決定用不用Normal Map,如果不用的話以後可以把這個關閉掉。
資源管理方面,有客戶說通常遊戲裡面跑到一段時間發生卡頓,我們調查發現是做了Shader編譯,我們引擎提供一個功能是Shader.WarmupAllShaders,推薦的使用方式是遊戲場景載入完之後,可以呼叫這個API,把你場景當中引用的Shader幫你預先編譯一下,這樣遊戲過程當中再使用的時候就不會再去呼叫編譯的操作,這樣就避免你遊戲過程當中產生Shader編譯導致的卡頓。
現在Unity官方不再推薦大家使用Resources資料夾,我們未來可能把這個功能關閉掉也是有可能的,因為你把資源放在這裡面的話,它是有幾個缺點的,第一個缺點你遊戲啟動的時候,比如說我們手機上面啟動這個遊戲,它第一步會把Resources資料夾內的檔案構建一個索引,這樣你後面再動態載入資源的時候,他可以在這裡面查詢這個檔案,這樣做導致遊戲啟動比較耗時,會發現啟動黑屏的時間很長,這樣對玩家來說這樣的體驗不太好。
另外,構建索引會佔用你更多系統的記憶體資源。所以說我們建議以後大家不要使用Resources資料夾。
Memory的問題、因為Unity使用C#語言託管了記憶體的釋放,導致開發者不能選擇在什麼時間去釋放記憶體。如果你的場景非常複雜的話,它需要遍歷場景中的所有物件,C#的GC操作會非常耗時。很多遊戲裡面你玩的過程當中發現遊戲卡頓都是記憶體GC導致的卡頓,關鍵的一點是遊戲過程當中,尤其是每幀的操作的函式裡面,儘量不要在堆疊分配記憶體。
首先,OnGUI是Unity老的UI系統,現在不建議使用OnGUI。另外就是第三方的外掛NGUI,也是有它的不足。因為它使用C#開發,會導致堆疊的記憶體分配,執行時會導致記憶體的操作。
另外,我們還比較常見的一個問題就是現在手機遊戲對畫面要求越來越高了,過去兩年前很少見到手機遊戲用後期特效,現在很多遊戲把後期特效開啟,後期特效其實有多個問題,首先它的GPU消耗比較高,另外一個消耗是會導致你的記憶體消耗非常大,因為每個特效都有可能分配你一個全螢幕大小的一個RenderTexture。而RenderTexture因為要用來實時渲染,所以是不能壓縮,不像普通的遊戲紋理可以使用ETC或者PVRTC格式壓縮。所以它對記憶體的佔用非常高,我們經常看到有的遊戲後期特效分配了幾十兆甚至更高的記憶體。
另外,我們發現過很多次正常不應該出現的情況,就是有些不需要Alpha通道的紋理在匯入時保留了Alpha通道。我們建議大家都檢查一下,把這些不必要的Alpha通道都關閉掉。
下面講一些Project Review常用效能分析工具、我們過去最常用還是Unity Profiler、Unity Memory Profiler、Xcode Instrument。
Unity Profiler有一個功能可以把效能分析資料儲存,很多開發者並不熟悉。有的時候你發現一個不方便的地方,某個版本測了一個數據,過兩天更新版本再測資料想做對比,上一個版本資料找不到,對比也不好對比,比較麻煩。有這樣一個功能,我相信還是有很多開發者沒有用過。執行的過程中把效能分析資料記錄下來儲存成一個檔案,想看過去版本效能資料的時候,可以再把這個檔案重新載入到Profiler窗口裡面,可以從這個窗口裡面看過去記錄下來的分析資料。
然後這是我們5.3提供的一個記憶體效能分析工具,主要特點就是圖形化的檢查哪一部分記憶體佔用比較大,我們去年Unity介紹過,今年還是給大家介紹一下,圖形化可以一眼看到哪些資源佔用記憶體最多,我首先優化佔用記憶體最多的資源,如果你去優化一個幾十K的資源意義會更小一些。
下面介紹很多開發者問的Profiler的一些選項,也是簡單給大家介紹一下。Overhead其實4.x就有了,這是Profiler統計不到的時間都會扔到這裡面。Unaccounted是5.x新出現的,和Overhead類似。正常情況下這項不會太高,如果發現有很高的情況有可能是引擎的Bug,如果可以把你的場景作為Bug提交給我們官方是最好的。
你的場景裡面越複雜,有越多的物件、越多的資源都會導致這兩項變多,最直接的優化方式就是把你的場景變得更簡單,讓它的物件更少。
我們還有幾個客戶反映過遊戲裡面有一個選項OnTransformChanged比較多,這主要是UI的消耗,一般UI層級越淺消耗越小,建議UI層級儘量變得少一點。
另外我們在5.3有一個OnTransformChanged的Bug,這是引擎開發過程當中出現的一個失誤,我們在5.5去修掉這個Bug,如果你發現你的遊戲裡面這項比較高,而且用的5.3的話,建議你把引擎升到5.5,這一塊會有比較大的優化。
還有開發者問過String.memcpy是什麼。Unity裡的Struct的賦值是通過String.memcpy實現的。優化可以考慮把每個變數單獨賦值,而不是使用Struct的整體賦值,它的效能有可能提升,建議測試對比一下效能有沒有變化,再選擇使用哪一種方式。
還有有開發者問過PutGeometryJobFence耗時比較多,對網格體頂點進行操作,這種操作就會產生這個消耗,一般是因為使用了很多粒子系統,LineRenderer或者Trail。
我們還有比較常用的是蘋果的Instrument,這個工具比較大的優勢是可以看到引擎底層函式的消耗,對你分析效能的原因有所幫助,這些工具我們在明天有一場演講詳細介紹,這裡不再詳細講,Allocation也是蘋果裡面自帶的一個功能,還有Capture GPU Frame也會在明天的演講內講。
安卓上面沒有太多好用的工具,相對蘋果來講功能少太多,這裡不詳細介紹。
這是我們中國區的技術支援團隊正在開發的效能測試平臺,這個平臺現在只有一個代號,正式名稱還沒有定下來,明天國內技術專場最後一場我的同事會介紹這個平臺開發的進度。
經常會有開發者問我哪一個版本的Unity Bug最少,這個問題很難回答,但是我可以給大家一個建議,你怎麼去選擇適合你的版本。
首先,介紹一下我們Unity版本現在是什麼策略釋出的,目前我們Unity同時維護三個大版本,我們釋出了5.6之後,我們會支援5.4、5.5、5.6版本的維護。如果大家選引擎版本的話,儘量還是選擇仍然在維護的版本,不要現在開一個專案再去用5.3。如果你的專案剛立項的話建議選擇比較新的版本。如果馬上就要上線了,因為5.6剛出來,也不會建議你用5.6的最新版本,因為剛出來的可能Bug多一點,可能到點5.6.1或者5.6.2Bug會少一些,如果你的專案剛開始做5.6沒有問題,我們大部分客戶現在5.5比較多。
然後,還有我們小版本的更新策略,假如我們現在是5.5.1f1,後面如果修Bug的話就會到P1-P2-P3-P4,5.5.1p4之後會是5.5.2f1。其實從5.5.1p4到5.5.2f1同p1到p2沒有區別,都是在修Bug,很多開發者看到小版本號增加了就非常緊張,其實小版本增加版本號的話,都是在修Bug,不會增加新的功能,這是我們小版本的一個釋出策略。另外我們的版本號只會增加不會減少,也不會停在某一個版本發兩個安裝包出來,都是不會的。
另外遊戲開發中不可避免有引擎升級的可能性,我們有一次幫客戶從5.3升級到5.5的案例。這次升級裡面,我們發現這個升級裡面,Unity 5.5.0打包Assetbundle速度變慢,確實是引擎出的一個Bug,短時間沒有那麼快修復,日本的團隊提供了一個工具在一定的時間內修復,這是一個連結,開源的工具。
還發現關於Lua指令碼提示Light.lightmappingMode檔案丟失,不認識這個引數,這個問題確實挺奇怪,大家注意一下。Light是在UnityEngine名空間的,但是Light.lightmapMode是在UnityEditor名空間的,不允許在執行時設定這個引數。
另外還發現編譯時提示檔案丟失,如system.data.dll,因為Unity在5.5升級了C#的編譯器,編譯檢查會比過去更嚴格。你可以檢查一下,重新拷貝這個檔案,或者更新一下這個dll檔案。
5.5提供新的安卓打包系統Gradle,我們這次升級當中發現了異常,unityexception:unknown project type。通過設定成ADT方式解決了這個問題。
Bug處理方面,我們開發者可以提供Bug到我們的QA團隊,他們會及時檢查你的Bug,安排研發人員進行修復。接下來的講座會給大家介紹怎麼去提交Bug,以及需要注意的各種事項,這裡不再去介紹了。
最後,就給大家再介紹幾個常見的問題。很多開發者過去給我們提過這個問題,發現Android Assetbundle記憶體問題,安卓上面的記憶體消耗比較大,我們在5.6把這個問題現在已經解決掉了,下面Assetbundle只有32k的記憶體分配,下一個5.4和5.5的Patch版本也會修復這個問題;
另外,Unity 5.5中Particle System記憶體佔用變高,5.3是佔了10kb,5.5佔了30kb;
還有的問題是如果Assetbundle內的Shader使用Shader Feature,我們提供一個功能叫Shader Variant Collection的東西,來解決shader載入特定變體的問題。
還有一個問題,從Assetbundle載入lightmap,還原renderer的LightmapScaleOffset對static batch的物體失效。目前的解決方法是不使用預設的靜態合批,而是在還原LightmapScaleOffet之後,使用CombineMesh API來做靜態合批。
還有很多專案遇到的構建工程太慢,我們遇到一個專案工程構建可能需要四個小時,我們可以用Cache Server加快資源匯入的過程。
最後一個問題不是非常常見,但是如果你想截圖提高解析度的話,它可以提供4倍、8倍解析度的截圖。