UWA 六月直播季 | 6.8 移動遊戲加載性能和內存管理全解析
https://blog.uwa4d.com/archives/livebroadcast6-8.html
因爲這篇文章沒有提供PPT供參考 所以寫這一篇文章來記錄一下1個多小時的視頻中講解的哪些優化點,
文章中的圖片都是UWA收集的
UWA優化法則之一
如果你不能"定位"它,就沒辦法"優化"它
"If you cannot measure it you cannot improve it." ---Lord Keivin
加載模塊
- 核心問題
- 加載耗時瓶頸
- AssetBundle加載/卸載是否合理?
- 資源加載/卸載是否合理?
- 實例化操作是否合理?
- 資源冗餘怎麼辦?
加載耗時瓶頸
函數名稱:
- Loading.UpdatePreloading
- GarbageCollectAssetsProfile 資源卸載
- Loading.AwakeFromLoad 資源加載
- LoadingReadObject
- Texture.AwakeFromLoad
- Shader.Parse
- Application.LoadLevelAsync Integrate GC耗時
- GC.Collect
- UnloadScene GameObject 銷燬
自定義邏輯代碼
- AssetBundle和資源加載\實例化\動態合批等
- Loading.ReadObject
- Loading.LockPresistentManager
- Loading.LoadFileHeaders
- AssetBundle.LoadAssetAsync
更爲具體的加載耗時
- Resource.Load加載
- AssetBundle.Load加載
- LoadFromeFile加載(推薦)
如何去優化
合理使用資源
- 紋理資源
- 紋理格式
- 分辨率
- Mipmap
https://blog.uwa4d.com/archives/LoadingPerformance_Texture.html
- 網格資源
- 頂點數
- 頂點屬性
- Read/Write
https://blog.uwa4d.com/archives/LoadingPerformance_Mesh.html
- 動畫資源
- 壓縮格式
- 數據精度
- 動畫類型
https://blog.uwa4d.com/archives/Loading_AnimationClip.html
動畫資源:4000幀,133s,58根骨骼
降低精度
KeyFrame-Opt降低數據精度,從8位減至3位
動畫類型
Generic
Humanoid(建議) 性能提升,降低AnimationClip數量,降低使用的種類
- Shader
- KeyWord 數量
https://blog.uwa4d.com/archives/LoadingPerformance_Shader.html
Keyword的降低確實可以大幅降低Shader的解析時間,進而提升加載效率。
- 音頻資源
- 包體大小 在音質允許的情況下首推MP3格式
- 內存大小 雙通道,加載類型
- LoadType 加載類型
- Decompress On Load 加載時解壓,然後以非壓縮的形式放在內存中
- Compressed In Memory 保留壓縮格式在內存,使用時解壓
- Streaming 在本地以文件流的形式讀入解壓播放(此方法使用最少量的內存來緩衝從磁盤中逐步讀取並在運行中解碼的壓縮數據)
- Compression Format 壓縮格式
- PCM (高清格式)
- Vorbis(OGG)
- ADPCM(輕度壓縮的高清格式)
- MP3(Android)
- LoadType 加載類型
- 加載效率
- Compressed + Vorbis 1.0x
- 其他格式 + Vorbis
- 4.0x(不開啓Load In Background )
- 1.0x(開啓Load In Background)
- 所有格式 + PCM
- 9.0x(不開啓Load In Background )
- 5.0x(開啓Load In Background )
- 運行壓力
- Decompress On Load(低)
- Compressed In Memory(中)
- Streaming (高)
佔用內存空間圖
Streaming << Compressed + Vorbis << 其他設置
Vorbis的Quality可以進一步控制,建議50%(個人使用1%效果還行)
音頻資源加載效率
1.0x 一倍數 n.0x n倍數
不急於播放的音頻,可以開啓Load In Background來提高加載性能,比如背景音樂
需要實時播放的音頻,比如開槍,走路,打擊就不要開啓了
運行時CPU消耗
內存佔用最小的 CPU消耗最大
總結一下:
- 合理使用資源
- 音頻資源
- 建議使用mp3格式的音頻文件
- 如果內存壓力過大,則可以考慮Streaming加載方式或較小Qulity質量的Vorbis格式
- 如果是非及時使用音效,建議開啓Load In Background來提升加載效率
- 如果存在大量頻繁使用音效,建議選擇Decompressed On Load來降低CPU開銷
- 自己壓縮,建議採用 Gzip+LoadFromFile(Async)
- 音頻資源
Unity官網鏈接
https://docs.unity3d.com/Manual/class-AudioClip.html
粒子系統
粒子系統經常使用,也經常疏忽
粒子系統加載Material耗時非常大,單獨加載多個粒子耗時會翻倍
建議一個AssetBundle包中保存多個粒子,一次性加載多個粒子的耗時增加相對來說少很多
- 粒子系統優化
- 材質剝離
- 數量
如何優化
- 更完善的加載/卸載管理
- AssetBundle加載
- 加載方式
- new WWW
- LoadFromCacheOrDownload
- LoadFromFile
- 優化方式
- unity5.3版本以後,建議將AB直接以LZ4格式進行發佈
- 如果本地加載,建議使用LoadFromFile(Async)來加載
- 根據機型的不同,選擇合適的Coroutine次數
- 加載頻率
- 駐留情況(不要卸載後立馬加載)
- 加載錯誤(不要加載不存在的文件)
- 特例緩存(緩存加載時間過長的資源)
- 加載方式
- AssetBundle加載
測試實驗數據 AssetBundle壓縮格式
測試加載方式: 紅米Note2
測試結果:ETC1 ,測試100次取平均值
LoadFromCacheOrDownload爲什麼LZMA很快(因爲第一次加載後緩存了)
測試結果:RGB24 ,測試100次取平均值
測試結果
AssetBundle加載問題-Coroutine次數
因爲每加載完一個AssetBundle後就yield return跳過當前幀
導致加載小的零碎資源包時CPU沒有跑滿,也就導致了加載總時間過長
AssetBundle打包
自己壓縮,建議採用 Gzip+LoadFromFile(Async)
壓縮比例圖
解壓時間圖
壓縮時間圖
以上是AssetBundle的說明和加載解壓方式的比較
加載頻率,駐留情況
從上圖我們可以發現問題,這個資源被加載和卸載了很多次
但是內存駐留的情況卻是一直常駐
這是因爲每次卸載資源後立刻加載了資源,導致了性能上的浪費
同步異步加載時間對比
AssetBundle.Load VS AssetBundle.LoadAsync
LoadALL VS Load OneByOne
做一個特殊的測試
使用10張相同的 ETC1格式 1024*1024分辨率 LZ4壓縮格式 在 紅米Note2上測試加載效率
AssetBundle資源加載小結
- 切換場景時,儘可能使用AssetBundle.load來提升加載效率
- 儘可能使用LoadAll來加載資源
- 保證同時使用的資源打包在一起
- 小,細碎的同類資源打包在一起(Shader,ParticleSystem)
Instantiate實例化操作
優化實例化次數,添加緩存池
如何優化:
- 將頻繁Instantiate/Destroy的GameObject放入緩存池
- 將部分耗時資源進行預加載
Active/Deactive操作
Active/Deactive頻率和耗時
大部分情況下Active/Deactive比Instantiate/Detroy要好
有兩類GameObject建議不要頻繁切換
- 複雜的UI界面
- 帶動畫組件的GameObject(每次設置Active會調用動畫組件的初始化)
建議把不想顯示的GameObject移動到視野外面去,並把Component給disabled 掉,等需要的時候移回視野內並enabled
這樣就沒有重建的CPU開銷
UWA優化法則之二
勿以惡小而爲之,勿以善小而不爲 ---劉備
內存管理
-
內存使用是否合適
- 內存泄漏如何解決
統計市面上MMO遊戲和ARPG遊戲的資源分佈圖
紋理資源:(建議不要大於150MB)
紋理資源如何優化?(UWA mipmap工具 可以給紋理分辨率建議)
網格資源 (建議縮減到20mb以下)
優化Tangents數量
動畫資源
優化方式上文講解了 減少動畫精度,設置動畫模式
音頻資源 (建議小於15MB)
RenderTexture
- 控制分辨率(截屏的時候改變分辨率,使用完成後把分辨率改回來)
- 關注Antialiasing(抗鋸齒)
粒子系統
提高粒子系統利用率
資源冗餘
不同的AssetBundle包包含相同的資源
如何做到零冗餘?
https://blog.uwa4d.com/archives/1577.html
AssetBundle(SerializedFile)
-數量儘可能保持在60以下(特別是Android平臺)
5.6以前不論多小的AB都佔有0.5MB的內存空間,5.6以後降低至16KB
關注總量分配(1w幀<30/50MB)
UGUI建議1w幀分配內存小於30MB
NGUI建議1w幀分配內存小於50MB
關注一次性分配(1MB以上)
關注誰在分配
- 配置表解析(一般佔用60~80%的內存)
- new class
- string 操作
- Instantiate
- 格式轉換
內存泄漏
泄漏和緩存僅是一線之隔
- Asset
- AseetBundle
- GameObject
- 邏輯變量
每1000幀獲取準確的駐留堆內存和變量數
查找堆內存增量:
https://blog.uwa4d.com/archives/1766.html
平均三天即可大幅改善堆內存泄漏問題
UWA優化法則之三
空杯心態,用數據說話,一切經驗歸零
人之所以言之鑿鑿
是因爲知道的太少
---弗郎索瓦·基佐