1)Lua全局變量代碼規范
2)AssetBundle LockPersistentManager開銷
3)Unity內置字體在資源檢測報告中不算冗余資源
4)特定Android設備上,Adreno發生凍屏問題
5)Mask和RectMask性能上的區別
這是第238篇UWA技術知識分享的推送。今天我們繼續為大家精選了若干和開發、優化相關的問題,建議閱讀時間10分鍾,認真讀完必有收獲。
UWA 問答社區:answer.uwa4d.com
UWA QQ群2:793972859(原群已滿員)
Lua
Q:使用Lua語言作為腳本輔助開發已經非常流行了,但是Lua語言中的全局變量是一個令人頭疼的問題,因為無需聲明就可以使用、編譯器編譯不會針對重命名和覆蓋進行報錯,稍不留神就會覆蓋掉全局變量導致Bug,而且全局變量引用GameObject有可能會造成泄露。
大家在開發過程中,對於Lua全局變量會制定什么代碼規范嗎?例如:什么時候可以使用全局變量?如何聲明?如何規避覆蓋等問題,謝謝。
A:可以在Lua虛擬機啟動以后,在適當的時機執行一下luaGlobalCheck.lua文件,這個文件里面會設置一下_G的元表和元方法,通過重寫_newindex和 _index元方法的方式來做到禁止新建全局變量和訪問不存在的全局變量時提示錯誤。這樣可以做到避免隨意新建全局變量污染環境和覆蓋的問題。
luaGlobalCheck.lua代碼如下:
setmetatable(_G, { -- 控制新建全局變量 __newindex = function(_, k) error("attempt to add a new value to global,key: " .. k, 2) end, -- 控制訪問全局變量 __index = function(_, k) error("attempt to index a global value,key: "..k,2) end })
感謝馬三小伙兒@UWA問答社區提供了回答
AssetBundle
Q:觀察性能曲線,發現某一幀AssetBundle加載中,LockPersistentManager耗時比較大。請問這塊是否能夠優化?
A1:這說明當前幀或前幾幀中存在較大量的資源在通過LoadAsync來進行加載,其本質是所加載的資源過大所致,對自身資源進行合理優化可降低Loading.LockPersistentManager的開銷。另外,將異步加載換成同步加載,LockPersistentManager就不會出現了,但其總加載耗時是沒有變化的,因為總加載量沒變。
關於主要資源的加載優化,可參考如下鏈接:
《Unity加載模塊深度解析(紋理篇)》
《Unity加載模塊深度解析(網格篇)》
《Unity加載模塊深度解析(Shader篇)》
《Unity加載模塊深度解析之動畫片段》
《移動游戲加載性能和內存管理全解析》
該回答由UWA提供
A2:Unity 2019.4.1版本下,其實是bundle.LoadFromFileAsync在主線程的Integrate Asset中執行,和PreloadManager線程的LoadAssetAsync不能同時進行,必須要鎖,也就出現LockPersistentmanager,一直鎖到一方結束。
本質還是這塊實現不完善,可以用Spin Lock一直鎖到Application.backgroundLoadingPriority規定的時間再到下一幀就行了,不用一直鎖到一方釋放。
![]()
Unity 2019.4.11和2019.4.16修改了主線程讀Bundle和等鎖的問題:
![]()
![]()
我在Unity 2020.1.17版本出的iOS上測試是基本解決了:
![]()
但是還有個別異步加載主線程等鎖的現象,估計是資源太大收集依賴時間太長觸發的:
![]()
感謝燃野@UWA問答社區提供了回答
AssetBundle
Q:我們的項目工程中返現兩個界面的Prefab,都是用Unity自己的Arial字體生成的Bundle,上傳到資源檢測,但是在報告中並未看到內置的字體是冗余資源。
A1:這個Arial是屬於Unity內置資源,打包APK的時候是會被打進unity default resources里面的,所以AssetBundle中使用到了這個Arial字體都是引用關系,並不會打包進對應的AssetBundle中,因此看不到冗余是正常的。
使用AssetStudio打開APK包中的assets/bin/Data/目錄下的unity default resources就可以看到了,如下圖:
![]()
感謝Xuan@UWA問答社區提供了回答
A2:不建議使用Arial字體,在某些低端機上中文無法顯示,主要還是默認字體在不同機型上的不一樣。
感謝鄭驍@UWA問答社區提供了回答
Rendering
Q:特定Android設備上,Adreno發生凍屏(GPU掛起)的問題。
現象是屏幕凍住不刷新了,但是音樂和點擊UI的音效還可以播放。用Unity Profiler看CPU也沒異常和閃退。凍屏時抓到的錯誤日志可戳原問答查看,麻煩大家幫看下有什么啟發,謝謝!
A1:不確定堆棧是不是跟你一樣。之前用Mono包在小米手機上出現過一樣的情況,后面改成IL2CPP就沒復現了。
感謝劍影蒙殘@UWA問答社區提供了回答
A2:樓上這個辦法對於部分機型確實有效,不過有些MTK的手機還是會有類似的問題。我們項目也有類似的,花屏或者屏幕畫面卡死。感覺像是Unity合批出的問題,動態合批或者是GPU Instance。我們嘗試着把單個批次的GPU Instance數量降低會有所緩解,這個數量最好根據手機GPU型號做個適配。
感謝Jony@UWA問答社區提供了回答
A3:使用了Unity官方提供的GPU Instance方案來實現的。
https://github.com/Unity-Technologies/Animation-Instancing開始使用的是這個方案默認的Shader渲染了戰斗單位,導致了奇怪的閃退和崩潰,默認的Shader如下:
![]()
在這個Shader中的loadMatFromTexture函數調用了9次,loadMatFromTexture的實現如下:
![]()
可以確認這里的問題大概率是采樣次數太多導致,然后修改了就使用當前幀,不進行Lerp操作,且每個頂點只受兩根骨骼的控制,然后測試沒有崩潰,目前還正在和美術確認效果損失的接受程度,后來的代碼大概是這樣:
![]()
感謝盧永平@UWA問答社區提供了回答
UGUI
Q:在Unity UI中,Mask和RectMask性能上有什么區別嗎?
A1:RectMask2D:不需要依賴一個Image組件,其裁剪區域就是它的RectTransform的rect大小。
性質1:RectMask2D節點下的所有孩子都不能與外界UI節點合批且多個RectMask2D之間不能合批。
性質2:計算Depth的時候,所有的RectMask2D都按一般UI節點看待,只是它沒有CanvasRenderer組件,不能看做任何UI控件的bottomUI。
Mask:組件需要依賴一個Image組件,裁剪區域就是Image的大小。
性質1:Mask會在首尾(首=Mask節點,尾=Mask節點下的孩子遍歷完后)多出兩個Draw Call,多個Mask間如果符合合批條件這兩個Draw Call可以對應合批(Mask1的首和 Mask2的首合;Mask1的尾和Mask2的尾合,首尾不能合。)
性質2:計算Depth的時候,當遍歷到一個Mask的首,把它當做一個不可合批的UI節點看待,但注意可以作為其孩子UI節點的bottomUI。
性質3:Mask內的UI節點和非Mask外的UI節點不能合批,但多個Mask內的UI節點間如果符合合批條件,可以合批。
從Mask的性質3可以看出,並不是Mask越多越不好,因為Mask間是可以合批的。得出以下結論:
- 當一個界面只有一個Mask,那么RectMask2D優於Mask;
- 當有兩個Mask,那么兩者差不多;
- 當大於兩個Mask,那么Mask優於RectMask2D。
感謝你如暖陽@UWA問答社區提供了回答
A2:從多個Mask合批考慮樓上的結論是可以的,這里補充一下:Mask寫Stencil會有額外的OverDraw,Mask2D沒OverDraw,但每個Item都要和MaskRect比較,有一定的CPU開銷(Mask適用於Item很多的情況,Item少建議Mask2D)。
感謝羽飛@UWA問答社區提供了回答
A3:從UI合批的角度看,在同一層級中:
Mask是一個具有高優先級的特殊組件,會優先進行操作。Mask會改變自己和其中UI的Material,兩者不同。
RectMask2D是一個裁剪器,沒有特殊權限,其合批規則與其它普通組件相同。RectMask2D會改變其中UI的Clip Rect。故不在同一個RectMask2D下的UI組件不能合批。
在UI能否合批的原因中,猜測:
Different Rect Clipping是指從RectMask2D到普通組件,或反之Different Clip Rect是指兩個RectMask2D之間切換。
感謝Tao@UWA問答社區提供了回答
今天的分享就到這里。當然,生有涯而知無涯。在漫漫的開發周期中,您看到的這些問題也許都只是冰山一角,我們早已在UWA問答網站上准備了更多的技術話題等你一起來探索和分享。歡迎熱愛進步的你加入,也許你的方法恰能解別人的燃眉之急;而他山之“石”,也能攻你之“玉”。
官網:www.uwa4d.com
官方技術博客:blog.uwa4d.com
官方問答社區:answer.uwa4d.com
UWA學堂:edu.uwa4d.com
官方技術QQ群:793972859(原群已滿員)