unity优化冷启动时间/加载时间总结
本文一部分博主并未實踐過,只是做一個總結,如有錯誤,請指正
目錄
一.概念了解
二.優化目的
1.保證游戲流暢度的基礎上DrawCall越小越好
2.Statistics統計面板參數
3.打包編譯
三.優化方法
1.編譯配置方面優化
①.使用IL2CPP進行打包
②.強烈建議使用IL2CPP后端,如果使用IL2CPP,則可以忽略第6條。
③.攝像機的clipping planes用到足夠就好,越小回越少drawcall
④.檢查場景中的光源
?
2.代碼優化
①.Tolua綁定和Lua資源加載。
②.代碼文件可以編譯成.dll文件
③.注意設置Web請求的超時時長
④.一些compoment的update可以等loading結束后才執行,減少加載時每幀的開銷
⑤.Transform不能放在for循環,getcompoment也是。
⑥.setactive改造為設置進來時判斷是否與之前的值一樣。因為本身setactive每次真是調用都回有gc
⑦.string不能直接加
⑧.parent用setparent替換。
⑨.協程用得多,這塊盡量用update或lateupdate替換,因為協程本身在unity會創建實體來管理,會產生少量得gc
⑩.減少new waitforsecond的使用并且把他存在一個變量中
?.特效的order的問題,同一個材質的應該放在同一個order下,不同的材質一定要放在不同的order下。
?.去掉了加載模型后的卸載行為
?.Aup另一個線程去做gpu數據
?.減少不必要使用的插件
?.一些重復加載的資源,可以保存下來
?.字典的key不能用枚舉
3.資源優化
①.盡量少的使用Resources方式管理資源,建議使用AssetBundle的方式管理
②.紋理資源選擇合適的壓縮格式進行壓縮
③.模型優化
(1).網格資源
(2).LOD層級細節技術
(3).OcclusionCulling遮擋剔除技術
(4).Lightmapping光照貼圖技術
(5).Mesh合并
(6) 去掉多余的mesh
(8).骨骼動畫開啟optimizeGameObjects選項,減少骨骼運算。
(9).關閉?Read/Write Enabled?設置?
(10).使用Mesh壓縮?
④.音樂加載優化
⑤.資源重復利用
?⑥.Shader編譯時間過長。
⑦.調整層級,把相同的altas放在一個順序的層級里
⑦.資源審查
⑧.資源后處理
4.UI優化
①.有一些ui上掛了剛體,但其實ui是沒必要用剛體的,增加額外的組件會增加額外的開銷。(ngui會加上rigidbody)
②.移除ui圖片的read/write,mipmap
5.設計優化
①.啟動場景不放模型,只放UI
②.項目中添加一個Loading場景,這個場景會是游戲啟動的第一個場景。
6.內存優化
①.設定了若干包圍盒,勾畫出一塊塊小區域。一旦玩家離開包圍盒太遠,程序就把包圍盒里面的物件卸載出內存。包圍盒略微擴大,允許包圍盒重疊,并可以用多個包圍盒來定義一個區域。同一個場景物件只可以屬于一個區域,即使它的位置在多個區域內。(區域可以重疊)
②.放置Mono內存泄漏
參考:
?一.概念了解
?app冷啟動: 當應用啟動時,后臺沒有該應用的進程,這時系統會重新創建一個新的進程分配給該應用, 這個啟動方式就叫做冷啟動(后臺不存在該應用進程)。
?app熱啟動: 當應用已經被打開, 但是被按下返回鍵、Home鍵等按鍵時回到桌面或者是其他程序的時候,再重新打開該app時, 這個方式叫做熱啟動(后臺已經存在該應用進程)。
二.優化目的
1.保證游戲流暢度的基礎上DrawCall越小越好
DrawCall即為由CPU下達命令,調用OpenGL或DirectX接口進行解析并由GPU進行渲染顯示的過程稱為一次DrawCall。
在Unity中查看DrawCall參數,Window / Profiler 或者Ctrl+7 快捷鍵打開 Profiler性能分析器面板。
2.Statistics統計面板參數
? ? ? ? FPS(幀數):越大越好
CPU(處理器計算速度):越低越好
render thread(渲染線程,GPU渲染所需要的時間):越低越好
Batches(渲染批次):與DrawCall關聯,是Unity自動分類的渲染批次
Tris(三角面數):相機視野范圍內的三角面數量
Verts(頂點數):相機視野范圍內的頂點數量
SetPass calls:Unity中的Shader中包含很多Pass塊,每當GPU即將去運行一個Pass塊之前,就會產生一個“SetPass call”,在描述性能開銷上更有說服力
3.打包編譯
- 放到Plugins目錄下的貼圖不會打包進去
- 放到Plugins目錄下的dll會自動打包,代碼也會打包
- 放在Resources目錄下的資源會自動打包
- 放在StreamingAssets目錄下的貼圖和視屏資源會自動打包,且log日志里面沒有統計到
- 放在Standard Assets目錄下的貼圖不會自動打包
- Assets下的所有代碼都會打包
?
三.優化方法
相比于Android或者iOS原生App,Unity3D引擎開發的游戲在冷啟動時間上確實比較長。三星SM-N9008手機上的測試結果是一個不算大的項目,如果使用Mono后端編譯,則需要10秒左右的冷啟動時間,而如果使用IL2CPP后端編譯,則冷啟動時間為7秒左右。
1.編譯配置方面優化
①.使用IL2CPP進行打包
IL2CPP相比于Mono確實能夠加快冷啟動時間,這是可以預期的。因為在Mono編譯的情況下,每個.cs文件都是一個TextAsset文件,而所有的.cs文件都需要在冷啟動時候全部加載到內存中,這些碎片化的文件加載操作都會占用冷啟動時間。關于冷啟動需要加載哪些文件的分析,可以參考Unity3D游戲在啟動時都默認加載哪些資源。而IL2CPP會把所有的C#代碼編譯成C 代碼,然后再進行編譯、鏈接等操作,這樣就減少了C#、DLL所帶來的開銷。
②.強烈建議使用IL2CPP后端,如果使用IL2CPP,則可以忽略第6條。
③.攝像機的clipping planes用到足夠就好,越小回越少drawcall
④.檢查場景中的光源
場景里使用燈光,會影響了某些物體的陰影,讓drawcall變多,基本上放置一個environment light以及一個directional light就行了
?
?
2.代碼優化
①.Tolua綁定和Lua資源加載。
這種是每次游戲啟動都會有的,ToLua接口綁定需要一定的時間,我們在確保前期不會使用Lua的情況下采用多線程的方式進行綁定和加載,保證主線程不會卡住。
②.代碼文件可以編譯成.dll文件
減少大量TextAsset文件導致的碎片化加載時間。
③.注意設置Web請求的超時時長
在游戲啟動的時候做了一些hook的事情,會有Web請求,后來我們遇到一個情況是在很多機器上會黑屏等待30s甚至60s這樣的時長,后來發現是因為這個Web請求沒有設置超時時間,于是使用了機器默認的超時時間,在不同設備上不同,比如紅米2A上會有接近1分鐘的超時限制。這個很坑,只是因為那個非必須的Web服務沒有正確開啟,導致排查了很長時間。
Native層增加界面,減少黑屏等待,提升玩家體驗。這個并不能真正解決問題,只是一種緩解手段,等到優化做到位了,其實也就不需要了。
④.一些compoment的update可以等loading結束后才執行,減少加載時每幀的開銷
⑤.Transform不能放在for循環,getcompoment也是。
⑥.setactive改造為設置進來時判斷是否與之前的值一樣。因為本身setactive每次真是調用都回有gc
⑦.string不能直接加
⑧.parent用setparent替換。
⑨.協程用得多,這塊盡量用update或lateupdate替換,因為協程本身在unity會創建實體來管理,會產生少量得gc
⑩.減少new waitforsecond的使用并且把他存在一個變量中
?.特效的order的問題,同一個材質的應該放在同一個order下,不同的材質一定要放在不同的order下。
?.去掉了加載模型后的卸載行為
?.Aup另一個線程去做gpu數據
?.減少不必要使用的插件
像我為了使用easytouch中的swift手勢直接導入了一整個插件,因此有些小功能還是自己寫的好,而且還能優化安裝包大小,一舉兩得
?.一些重復加載的資源,可以保存下來
?.字典的key不能用枚舉
?
3.資源優化
①.盡量少的使用Resources方式管理資源,建議使用AssetBundle的方式管理
此項還未測試,因為公司初版不適用AB包方式
Resources目錄下面的所有資源會在ResourceManager中記錄下來,而ResourceManager就是一個文件,通常是一個YAML格式的文本文件。而這個文件是會在冷啟動時加載的。所以Resources目錄下面的有越多的資源,那么這個ResourceManager就會越大,加載時間也會越長。
使用Resources方式管理資源還有一個壞處,就是所有的資源都是統一管理的,這樣的資源的管理粒度沒辦法控制。建議使用AssetBundle的方式管理,這樣可以使用多個AssetBundle來管理資源。把在Loading場景中需要的最小資源集放在一個AssetBundle中,這樣在冷啟動時啟動Loading場景時,只需要加載一個AssetBundle即可。選擇合適的粒度管理AssetBundle,可以在合適的時候加載某一個AssetBundle,不使用時就可以卸載某一個AssetBundle。
在Loading場景中,添加一個進度條,然后同步加載進入主場景所需要的AssetBundle,這樣用戶就不會感到等待時間太煩躁了。同步加載要比異步加載時間更短。
減少冗余資源和重復資源方面:
A.Resources目錄下的資源不管是否被引用,都會打包進安裝包,不使用的資源不要放在Resources目錄下
B.不同目錄下的相同資源文件,如果都被引用,那么都會打包進資源包,造成冗余,保證同一個資源文件在項目中只存放在一個目錄位置
②.紋理資源選擇合適的壓縮格式進行壓縮
紋理資源在游戲中一般是最大的資源,選擇合適的壓縮格式進行壓縮,既可以減少內存占用,又能夠加快資源的加載速度。壓縮格式的選擇要從顯示效果和壓縮率上進行權衡。一般在Android上使用ETC格式,在iOS上使用PVRTC格式,在某些情況下,可能還可以考慮使用Alpha通道分離技術進行壓縮處理。
(1).嚴格控制RGBA32和ARGB32紋理的使用,在保證視覺效果的前提下,盡可能采用“夠用就好”的原則,降低紋理資源的分辨率,以及使用硬件支持的紋理格式。
(2).在硬件格式(ETC、PVRTC)無法滿足視覺效果時,RGBA16格式是一種較為理想的折中選擇,既可以增加視覺效果,又可以保持較低的加載耗時。
(3).嚴格檢查紋理資源的Mipmap功能,特別注意UI紋理的Mipmap是否開啟。在UWA測評過的項目中,有不少項目的UI紋理均開啟了Mipmap功能,不僅造成了內存占用上的浪費,同時也增加了不小的加載時間。
(4).ETC2對于支持OpenGL ES3.0的Android移動設備來說,是一個很好的處理半透明的紋理格式。但是,如果你的游戲需要在大量OpenGL ES2.0的設備上進行運行,那么我們不建議使用ETC2格式紋理。因為不僅會造成大量的內存占用(ETC2轉成RGBA32),同時也增加一定的加載時間。下圖為測試2中所用的測試紋理在三星S3和S4設備上加載性能表現??梢钥闯?#xff0c;在OpenGL ES2.0設備上,ETC2格式紋理的加載要明顯高于ETC1格式,且略高于RGBA16格式紋理。因此,建議研發團隊在項目中謹慎使用ETC2格式紋理。
(5).都去掉alpha通道,作為背景展示的圖片,基本都沒有透明要求,有特殊要求的則放到atlas里面
a. Loading圖這類需要比較精細的,則把圖片設置為Automatic TrueColor,設置真彩色,保證不失真
b. 地圖、縮略圖、UI背景圖等等要求不精細的,則可以設置為自動壓縮格式(有壓縮情況,都需要圖片寬高尺寸是2的冪,可以在Advance里面設置toNearest)
(6).關閉?Read/Write Enabled?設置
這個?Read/Write Enabled?的設置會造成貼圖在內存里變成兩份,一份在?GPU?上一份在?CPU?可以尋址的內存上。這是因為大多數平臺,把數據從?GPU?內存讀回?CPU?很慢。從?GPU?內存讀取一張貼圖到暫存區給?CPU?程序用(例如:Texture.GetPixel)會導致效能很差。這個設定在?Unity?里預設是關閉的,但要避免誤勾這個選項。?
?
注意:ios下會自動把圖片寬高拉伸為2的冪次方尺寸,這樣會導致圖片顯示失真,解決辦法是制作圖片的時候就保證是2的冪大小。如果圖片顯示的區域確實不能做出2的冪大小,可以用補黑邊的方式把圖片做出2的冪大小,設置圖片的時候,就需要調整圖片的UV
要點:android下,帶alpha通道的圖片,自動壓縮是以ETC2 8bit的方式壓縮的,不帶alpha通道,是壓縮成ETC 4bit的格式(ETC2 支持alpha通道),ios下是壓縮成PVRTC 4格式。手機硬件對各種格式圖片的加載效率不一樣,RGBA32是最慢的。所以需要對圖片進行處理,改壓縮方式,ETC和pvr是加載最快的。
③.模型優化
(1).網格資源
- 在保證視覺效果的前提下,盡可能采用“夠用就好”的原則,即降低網格資源的頂點數量和面片數量;
- 研發團隊對于頂點屬性的使用需謹慎處理。通過以上分析可以看出,頂點屬性越多,則內存占用越高,加載時間越長;
- 如果在項目運行過程中對網格資源數據不進行讀寫操作(比如Morphing動畫等),那么建議將Read/Write功能關閉,既可以提升加載效率,又可以大幅度降低內存占用。
(2).LOD層級細節技術
? ? ? ?此技術需要美工的配合,提供給程序多個不同三角面數的模型
在場景中新建一個空的游戲物體,并添加LOD Group組件,如下圖所示:
并將美工提供的三種不同精度的模型按照精度的大小依次拖入到LOD0、LOD1、LOD2中
此時,場景中渲染顯示的模型會根據相機與模型的距離進行切換顯示,具體的切換顯示距離可拖動組件中的條形框大小進行自定義,這樣便達到了近處渲染精模,遠處渲染粗模甚至不渲染來減少GPU消耗的目的
? ? ? ? ? ? ? ? ??
(3).OcclusionCulling遮擋剔除技術
? ? ? ?當場景中有大量模型需要渲染時,應用遮擋剔除可實現減少DrawCall提升性能的效果
首先選中所有需要進行遮擋剔除的模型,并設置其occluder(遮擋體)和occludee(被遮擋體),有的物體可以是遮擋體同時也是被遮擋體。
接下來Window / Occlusion Culling 打開遮擋剔除面板如下圖:
選中遮擋剔除選項,烘焙
烘焙完成后,設置好顯示視野的相機
(4).Lightmapping光照貼圖技術
首先將需要進行光照貼圖的游戲物體設置為Lightmap Static
其次將用于光照貼圖的所有光源設置為Baked模式
最后Window / Lighting 打開燈光面板,進行烘焙,面板如下
? 其中Build后會在當前場景所在的文件夾中生成一個光照貼圖文件,我們也可以點擊Clear Baked Data 按鈕進行光照貼圖的清理操作
之后無論場景中的光源是否激活,均顯示光照效果,效果圖如下:
·
(5).Mesh合并
?當場景中模型非常多,不妨試一下模型合并技術,可以在3dMax或其他建模軟件上進行操作,也可在Unity中進行操作,這里我僅介紹Unity中的模型合并方法。
前提:合并的物體必須是相同的材質,否則合并之后賦值多個材質并不能起到優化作用
首先,將下述代碼放在Assets / Editor 文件夾下
其次,在場景中需要合并的模型放在一個空物體下
然后,點擊選中空物體并點擊上方的菜單欄按鈕MeshCombine / CombineChildren進行合并所有子物體Mesh
最后,自行更改模型中的材質,位置等參數即可
using UnityEngine; using System.Collections; using UnityEditor;public class CombineMesh : MonoBehaviour {//菜單按鈕靜態觸發[MenuItem( "MeshCombine/CombineChildren")] static void CreatMeshCombine(){//獲取到當前點擊的游戲物體Transform tSelect = (Selection.activeGameObject).transform;//如果當前點擊的游戲物體無子物體,則無操作if (tSelect.childCount < 1){return;}//確保當前點擊的游戲物體身上有MeshFilter組件if (!tSelect.GetComponent<MeshFilter>()){tSelect.gameObject.AddComponent<MeshFilter>();}//確保當前點擊的游戲物體身上有MeshRenderer組件if (!tSelect.GetComponent<MeshRenderer>()){tSelect.gameObject.AddComponent<MeshRenderer>();}//獲取到所有子物體的MeshFilter組件MeshFilter[] tFilters = tSelect.GetComponentsInChildren<MeshFilter>();//根據所有MeshFilter組件的個數申請一個用于Mesh聯合的類存儲信息CombineInstance[] tCombiners = new CombineInstance[tFilters.Length];//遍歷所有子物體的網格信息進行存儲for (int i = 0; i < tFilters .Length ; i++){//記錄網格tCombiners[i].mesh = tFilters[i].sharedMesh;//記錄位置tCombiners[i].transform = tFilters[i].transform.localToWorldMatrix;}//新申請一個網格用于顯示組合后的游戲物體Mesh tFinalMesh = new Mesh();//重命名MeshtFinalMesh.name = "tCombineMesh";//調用Unity內置方法組合新Mesh網格tFinalMesh.CombineMeshes(tCombiners);//賦值組合后的Mesh網格給選中的物體tSelect.GetComponent<MeshFilter>().sharedMesh = tFinalMesh;//賦值新的材質tSelect.GetComponent<MeshRenderer>().material = new Material(Shader.Find("VertexLit"));}}效果圖如下:
?
(6) 去掉多余的mesh
(8).骨骼動畫開啟optimizeGameObjects選項,減少骨骼運算。
??ModelImporter.optimizeGameObjects?能夠優化骨骼動畫,將無用的骨骼合并,實際測試發現,設置此選項后的蒙皮骨骼動畫模型,不受動態縮放影響,只能保持導入的大小,大規模同屏角色肯定是效率有明顯的影響,但是對于動態改變模型大小的需求該方法不太適用。
打勾后所有的骨架對應的?Transform?結構都會被移除,如果模型骨架結構中有特定的部位需要露出方便控制(例如模型的手部要用來握住武器),則可以把它列在“ExtraTransforms”白名單中。?
?
(9).關閉?Read/Write Enabled?設置?
當項目執行時想用程序來修改?Mesh,或者如果?Mesh?要用作?MeshCollider?的話,這里需要打勾。反之如果模型沒用在MeshCollider,也沒用程序來修改?Mesh?的話,關閉這里可以省下一半的內存。?
(10).使用Mesh壓縮?
開啟?Mesh compression?選項會縮短用來表示模型數據不同信道的浮點數字元長度,這會移除一定的精確度并可能造成可見的變化,使用這個之前最好先讓美術檢查過這種損失在允許范圍內。?
各個壓縮等級使用的位長度在?ModelImporterMeshCompression?腳本里有介紹。?
請記得,可以針對不同信道使用不同等級的壓縮,所以項目可以只針對切線向量(Tangent)和法向量(Normal)壓縮但不壓縮?UV?和頂點位置。
?
④.音樂加載優化
(1).Mac / PC 適用于 Ogg Vorbis格式音頻,而Mp3適用于移動端,不過音質會下降
? ? ? ? ? ? ? 長時間音樂(背景音樂)壓縮格式:mp3
短時間音樂(攻擊等等)一般不壓縮存儲格式為:wav
(2).加載模式
?
Decompress On Load:適用于小文件
Compressed in Memory:使用于大文件
Streaming:以流的形式便加載邊播放(對CPU消耗較大一般不采用)
如果是交互的音效應該不能壓縮,不然因為unity要解壓,需要耗時所以點擊時不能做到實時。關鍵再選擇PCM
?
(3) .降低音頻的取樣
調低取樣能進一步降低內存消耗和最終項目的大小,可以和音效設計師協調找出最小最能接受的音源質量。參考SetCompressionBitrate。?
(4).強制音效用單聲道?
只有少數的手機裝置真的有立體聲喇叭,而將音效強制設定為單聲道能讓內存的消耗減半。就算游戲會輸出部份的立體聲,有些單聲道像是?UI?音效還是可以開啟這個選項。
(5).采用平臺支持的壓縮設定?
采用硬件支持的音源壓縮格式。所有的iOS設備都有?MP3?硬件解壓縮能力,而大多數的?Android?設備都有支持?Vorbis。
此外,可以直接將未壓縮的聲音文件導入?Unity?里,因為?Unity?會在打包項目時會重新壓縮。所以不需要先壓縮再導入Unity,這只會降低音效質量。
?
⑤.資源重復利用
unity scrollview 優化 高效重復利用 避免大量初始化時間過長
類似該文章中可以進行加載顯示部分,然后再根據操作進行循環利用(可以使用資源池實現)?
?⑥.Shader編譯時間過長。
如果只有游戲安裝之后第一次啟動時間過長,一個很大的可能是shader編譯,之后游戲啟動因為有了Cache所以會快很多。這種情況的話建議查看下Always Include的Shader內容和變體,使用shadervariantcollection等方案替代。
(1)、Shader資源的物理體積與內存占用雖然很小,但其加載耗時開銷的CPU占用很高,這主要是因為Shader的解析CPU開銷很高,成為了Shader資源加載的性能瓶頸;
(2)、Mobile/Particles Additive在解析方面的耗時遠小于Mobile/Diffuse、Mobile/Bumped Diffsue甚至Mobile/VertexLit;
(3)、除Mobile/Particles Additive外,其他三個主流Shader在加載時均會造成明顯的降幀,甚至卡頓。因此,研發團隊應盡可能避免在非切換場景時刻進行Shader的加載操作;
(4)、盡量減少復雜的數學運算,盡量減少Discard操作
(5)、隨著硬件設備性能的提升,其解析效率差異越來越不明顯。
對于Shader資源的管理建議如下:
(1)、在保證渲染效果和項目需求的情況下,盡可能降低Shader的Keyword數量,以提升Shader的加載效率;
(2)、對于簡單Shader,可嘗試去除Fallback操作,該方法非常適合于目前正在大量使用的Mobile/Diffuse、Mobile/Bumped Diffuse等Built-in Shader;
(3)、盡可能對Shader進行單獨、依賴關系打包并對其進行預加載,以降低后續不必要的加載開銷。
?
⑦.調整層級,把相同的altas放在一個順序的層級里
調整前 :
?
調整后 :
?
如果遇上調整層級還是具有相同材質的靜態物體并沒放到一個drawcall,還是一個個繪制
?
?看了下這幾個繪制的物體receive shadow都是勾選的,所以問題應該出在了within the shadow distance這里。就是這些物體受到了不同的陰影影響。比如2塊石頭,一塊石頭在樹下,受到了樹影子的影響,被放到一個drawcall里,另一塊石頭就是沒有受到任何遮擋,所以直接被放在一個drawcall。它們就不能在一個drawcall里了。
因此要判斷是否需要陰影進行取出陰影:
?
cast shadows 設為off,取消勾選receive shadows。如果不需要讓它影響lightmap,取消勾選lightmap static
⑦.資源審查
對于較大規模的項目,最好準備一道自動的防線防范人為失誤。例如寫一段簡單的檢查程序確保沒有任何人能在項目加入一張沒壓縮的?4K?貼圖。?
或許你會覺得不可能,但這問題我們真的很常見。沒有壓縮的?4K?貼圖會占用大約?60mb?的內存空間,在低端的手機設備(例如?iPhone 4s)上,整個項目用掉超過?180mb~200mb?就會很危險。有時候你的游戲在好的手機上跑沒問題,在差的手機上跑會宕機,不一定是硬件的問題。如果犯這種錯誤,這張貼圖會無端占用應用程序四分之一到三分之一的可用內存,造成很難追蹤的內存不足錯誤。?
⑧.資源后處理
Unity?編輯器里的?AssetPostprocessor?類別可以用在?Unity?項目上實行某些基本限制。這個類別在資源導入時會收到一個回調。使用方法即繼承?AssetPostprocessor?并實作一個或多個?OnPreprocess?方法,重要的包含:?
OnPreprocessTexture?
OnPreprocessModel?
OnPreprocessAnimation?
OnPreprocessAudio?
public class ReadOnlyModelPostprocessor : AssetPostprocessor {public void OnPreprocessModel() {ModelImporter modelImporter = (ModelImporter)assetImporter;if(modelImporter.isReadable) {modelImporter.isReadable = false;modelImporter.SaveAndReimport();}} }?這是一個簡單的?AssetPostprocessor?限制規則范例?
每當導入模型到項目或模型的導入設定(Import settings)被修改時會呼叫這個類別,這里程序只是檢查可否讀寫模型的設置?isReadable?屬性,如果是?true?就會改為?false,存盤后重新導入資源。?
請注意,呼叫?SaveAndReimport?會導致這段程序會被再次呼叫!但由于設置已經被改為?false,所以不會無窮遞歸下去。?
?
4.UI優化
①.有一些ui上掛了剛體,但其實ui是沒必要用剛體的,增加額外的組件會增加額外的開銷。(ngui會加上rigidbody)
②.移除ui圖片的read/write,mipmap
?
5.設計優化
①.啟動場景不放模型,只放UI
公司初版APP模型很大,也是放在本地,但是我在第一個場景初始化的時候加載了模型,更改之后快了10s左右
②.項目中添加一個Loading場景,這個場景會是游戲啟動的第一個場景。
在Loading場景中盡量少的依賴,盡量少的紋理依賴、AssetBundle依賴、代碼依賴,總之,這個Loading場景一定要盡量少的依賴,這個場景一定要盡量簡單,這樣才能保證盡快的加載速度。
?
6.內存優化
在當下的手機及平板硬件設備條件下,操作系統留給應用的可用內存并不多,大約只有 500M 左右。
和 PC 環境不同,手機上是交換分區的機制來對應一些臨時突發性內存需求的。而手機必須保證一些系統服務(某些高優先級后臺業務)的運行,所以在接電話、收取推送等等意外任務發生時,有可能多占用一些內存,導致操作系統殺掉前臺任務讓出資源。根據實際測試,游戲想跑在當前主流高端手機上必須把自己的內存占用峰值控制在 400M 內存以下,350 M 會是一個合理的值
①.設定了若干包圍盒,勾畫出一塊塊小區域。一旦玩家離開包圍盒太遠,程序就把包圍盒里面的物件卸載出內存。包圍盒略微擴大,允許包圍盒重疊,并可以用多個包圍盒來定義一個區域。同一個場景物件只可以屬于一個區域,即使它的位置在多個區域內。(區域可以重疊)
?所有物件都標記分類出外觀物件和細節物件。比如一個城市的城墻就是外觀物件,而城內的所有東西都是細節物件;一片樹林的大顆植物是外觀物件,地面的花花草草是細節物件。一般情況下,大部分物件都默認是細節物件,只有少數需要遠觀的才標記成外觀。這點,其實原本就做了視距分層,只不過是為了在渲染時做顯示剔除用的,并沒有用于控制內存。而這次,需要對外觀物件和細節物件單獨打包分類,便于分開卸載。
當玩家處于一個區域內部時,必須保證這個區域的外觀物件和細節物件都加載到內存。如果之前并不在內存,也需要開啟異步加載的流程。當一個玩家距離另一個區域比較近時,只需要確保該區域的外觀物件在內存即可,可以卸載任何不在區域的細節物件。
②.放置Mono內存泄漏
(1)出現原因?
1. “忘記”清除對該無用對象的引用
并非只有顯示調用new才會分配內存,很多隱式的分配是不容易被發現的,例如產生一個List來存儲數據,緩存了服務器下發的一份配置,產生一個字符串等等,這些操作都會產生內存的分配。你分配幾十K,他分配幾十K,一會兒內存就沒了。?
其次,有一點需要說明的是,在Unity環境下,Mono堆內存的占用,是只會增加不會減少的。具體來說,可以將Mono堆,理解為一個內存池,每次Mono內存的申請,都會在池內進行分配;釋放的時候,也是歸還給池,而不會歸還給操作系統。如果某次分配,發現池內內存不夠了,則會對池進行擴建——向操作系統申請更多的內存擴大池以滿足該次的內存分配。需要注意的是,每次對池的擴建,都是一次較大的內存分配,每次擴建,都會將池擴大6-10M左右(此處無官方數據,是觀察所得)。
2.資源中的泄漏 – Native內存泄漏(資源加載之后占有了內存,但是在資源不用之后,沒有將資源卸載導致內存的無謂占用。?)
Unity的內存回收是需要主動觸發的(Resources.UnloadUnusedAssets()),GC也提供了同樣的接口GC.Collect()?用來主動觸發垃圾回收,Resources.UnloadUnusedAssets()內部本身就會調用GC.Collect(),Unity還提供了另外一個更加暴力的方式——Resources.UnloadAsset()來卸載資源,但是這個接口無論資源是不是“垃圾”,都會直接刪除,是一個很危險的接口,建議確定資源不使用的情況下,再調用該接口。為了避免游戲卡頓,建議在加載環節來處理垃圾回收的操作。
再來看一下為什么會有資源的泄漏。首先和代碼側的泄漏一樣,由于“存在該釋放卻沒有釋放的錯誤引用”,導致回收機制認為目標對象不是“垃圾”,以至于不能被回收,這也是最常見的一種情況。
針對資源,還有一種典型的泄漏情況。由于資源卸載是主動觸發的,那么清除對資源引用的時機就顯得尤為重要。現在游戲的邏輯趨于復雜化,同時如果有新成員加入項目組,也未必能夠清楚地了解所有資源管理的細節,如果“在觸發了資源卸載之后,才清除對資源引用”,同樣也會出現內存泄漏了。
還有一種資源上的泄漏,是因為Unity的一些接口在調用時會產生一份拷貝(例如Renderer.Material參考https://docs.unity3d.com/ScriptReference/Renderer-material.html),如果在使用上不注意的話,運行時會產生較多的資源拷貝,造成內存的無端浪費。
?
具體請看 :?Unity中的內存泄漏
?
參考:
App冷啟動、熱啟動介紹以及優化啟動的實現方式,解決啟動白屏問題
在Unity3D游戲如何加快冷啟動時間
Unity啟動耗時優化
iOS 優化程序冷啟動時間
關于Unity加載優化,你可能遇到這些問題
unity3d 加載優化建議 總結 from 侑虎科技
unity scrollview 優化 高效重復利用 避免大量初始化時間過長
關于Unity性能優化的一些方法
unity加載優化小結
批處理優化(官方鏈接)
Unity3D性能優化最佳實踐(四)資源審查
unity-Profiler調試Android的正確姿勢(mumu模擬器)
unity 打包編譯記錄
Unity3D 的大場景內存優化
Unity中的內存泄漏
資源加載性能測試代碼
總結
以上是生活随笔為你收集整理的unity优化冷启动时间/加载时间总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 台式计算机mtbf,电子产品整机MTBF
- 下一篇: 【DiscuzX2】DiscuzX2的u