轉載自:https://blog.csdn.net/m0_37283423/article/details/84378384html
● 儘量使用for來代替foreach:每次foreach會產生一個Enumerator,迭代器會額外分配內存。緩存
● 儘可能避免使用Lambda表達式:存在內存泄露隱患。安全
● 儘可能避免使用LINQ:部分功能沒法在某些平臺上使用,且會分配大量GC Alloc。架構
● 控制StartCorountine()的次數:開啓一個協程,至少分配37B的內存(Coroutine類的實例 - 21B;Enumerator - 16B)。編輯器
● 使用StringBuilder來代替String進行字符串拼接:StringBuilder.Append方法在拼接字符串時,變化老是發生在同一個內存塊中;而String + String + ...這種字符串拼接方式,會頻繁申請內存並釋放,致使GC頻繁調用。函數
● 緩存組件:每次GetComponent均會分配必定的GC Alloc;每次獲取對象名稱Object.name(實際爲Object.get_name())會分配39B(具體大小視實際狀況而定)的堆內存。性能
● 避免使用開銷大的函數:如GameObject.Find、GameObject.FindWithTag、Object.FindObjectOfType等查詢方法。測試
● 使用GameObject.CompareTag代替GameObject.tag:GameObject.tag會在內部循環調用對象分配的標籤屬性並分配額外的內存。優化
● 使用ObjectPool對象池來管理對象:避免頻繁的Instance和Destroy,這兩個操做都挺耗性能的。動畫
● 儘可能不要在Update()函數中作複雜計算:如若須要,能夠隔N幀計算一次。
● 儘可能減小函數調用棧:如用x = (x > 0 ? x : -x)代替x = Mathf.Abs(x)。
● 紋理壓縮格式:iOS使用PVRTC格式;Android使用ETC格式;Windows使用DXT格式。
● 凡是3D場景,都應該儘量啓用MipMaps。若是硬件MipMaps沒法知足效果要求:一、使用本身生成的Mipmaps;二、使用Aniso。
● 若是紋理用於UI或2D場景,禁用MipMaps。
● 經過減色的方式下降紋理大小。
● 建議總內存控制在150MB如下;堆內存控制在40MB如下。
● 切換場景時避開內存峯值。當前一個場景還未釋放就切換到新場景,這時因爲兩個場景的內存疊加容易形成內存峯值。能夠採用在屏幕中間遮蓋一個Loading場景,在舊場景釋放完成,而且新場景初始化結束後,再隱藏Loading場景。
● 使用Prefabs(凡是場景物體,都應該製做成Prefabs)。
● 經過ObjectPool對象池來避免內存的頻繁操做,從而避免內存碎片影響到大內存塊的申請;嘗試在切換場景時不釋放公共UI資源。
● 經過LoadManager,保證在同一時間段內僅載入一個WWW對象,實現順序加載。
● 紋理內存佔用過大:峯值 < 50MB。
● 內存泄露:內存需保持升降一致,避免泄露。
● 網格資源內存過大:峯值 < 20MB。
● 動畫片斷:內存 < 15MB,警戒資源泄露。
● 音頻資源:內存 < 15MB,警戒資源泄露。
● DrawCall數量:峯值 < 250,主體範圍(5% - 95%)應在(0 - 200)個以內。
● Triangle數量:峯值 < 100000/幀。
● VBO上傳量:峯值 < 5MB,頻繁加載的資源使用緩存池緩存。
● Skinned Mesh數量:峯值 < 50,對應Profiler中的MeshSdinning.Update、Animator.Update。
● RenderTexture:數量 < 10。
● Rigidbody數量:峯值 < 50/幀,對應Profiler中的Physics.Simulate。
● 碰撞體數量:峯值 < 100/幀,對應Profiler中的Physics.Simulate。
● 採用依賴性打包
● Assetdatabase.GetDependencies
● Push / Pop
● WWW vs. CreateFromFile
● WWW常被用於加載採用Unity標準壓縮方法壓縮過的AssetBundles。
● CreateFromFile只能加載非壓縮格式的本地AssetBundles;能夠先採用其餘壓縮格式進行壓縮,下載到本地後自行解壓,再行加載和使用。
● AssetBundle.mainAsset的功能每每被忽視
● 它能夠是標準的資源asset,用來存儲AssetBundles中最重要的資源文件。
● 也能夠是TextAsset,其中能夠包含任意內容,推薦用來記錄每一個AssetBundle中的物體列表和信息描述。
● 問題:當修改AssetBundles中的內容時,須要從新Build這些AssetBundles才能使其生效。這個過程每每很是耗時並影響開發效率。
● 開發階段和發佈階段使用不一樣的策略:
● 爲了提升在Unity Editor中反覆修改AssetBundles的調試效率,推薦開發時使用Resources.LoadAssetAtPath來避免從新創建AssetBundles。
● 在發佈時才使用惟一的腳本打包AssetBundles。
● AssetDatabase.ImportAsset有三個重要事實:
● 它是將一個外部asset轉化爲Unity內部可以識別的internal asset,但並不實際在內存中加載asset,更沒有返回值。
● 它會根據AssetImporter中的相關設定對asset的相關屬性進行修改,儘管兩個API之間沒有任何的參數傳遞。
● 它經常被用於在調用BuildPipeline.BuildAssetBundle前強行從新導入一個asset。
● 幾種經常使用的AssetImporter類型:TextureImporter、ModelImporter及MovieImporter。
● AssetPostprocessor的做用
● AssetPostprocessor能夠在import每一個asset以前和以後分別自動觸發AssetPostprocessor.OnPreprocessXXX和AssetPostprocessor.OnPostprocessXXX。
● 方便用戶介入和修改資源導入的過程。
● 自動編譯Player
● 支持命令行進行編譯。
● 編寫編譯腳本,並放在Assets/Editor目錄下。
● 腳本中聲明一個類,包含一個靜態方法,經過BuildPipeline.BuildPlayer來實現編譯工做。
● 編譯後處理腳本
● Unity支持在編譯好可執行程序以後,經過後處理腳本對其進行必定的修改,例如製做安裝文件等。
● 在Windows平臺下,能夠在編輯器腳本(Editor Script)中使用BuildPipeline.BuildPlayer方法來進行編譯,並在其後添加任意的後處理代碼。
● 在Mac平臺下,Unity在編譯工程後會自動查找一個名爲PostprocessBuildPlayer的後處理腳本文件,用於實現編譯後處理;後處理腳本能夠是sh、perl或任意與命令行兼容的語言。
● 對移動芯片的支持
● 從Unity 4.0開始,Unity中止了對ARM V6架構的支持。
● Unity 3.5.x版本仍舊支持ARM V6架構。
● Graphics Emulation
● 在不使用實際硬件設備的前提下,在Unity編輯器中就能夠模擬測試不一樣圖形硬件對當前項目中所使用的圖形API的支持能力(對Editor->Graphics Emulation進行設置)。
● 發佈包的代碼保護
● Unity腳本在iOS平臺下是安全的,與是否使用AssetBundle無關。
● 對於Android和其餘平臺,能夠採用AssetBundle + TextAsset的方式進行,也能夠採用代碼混淆的方式進行。
● 在全部平臺下都可使用Native DLL。
● 發佈包的代碼加密
● 需經過AssetBundle和TextAsset來實現,即把代碼編譯爲TextAsset,並打包入AssetBundle中,參考官方文檔:「Including scripts in AssetBundles」一節:http://docs.unity3d.com/Documentation/Manual/scriptsinassetbundles.html
● 其中TextAsset並非真正意義上的Text,而是編譯好的dll文件,是以binary形式存在的。參考官方文檔「Text Asset」中的「Binary data」一節:http://docs.unity3d.com/Documentation/Components/class-TextAsset.html
● 發佈包的美術資源加密
● 對於全部平臺,最多見的是對貼圖進行加密,經過AssetBundle和TextAsset來實現。
● 程序發佈後的增量更新
● 原理:Unity腳本通過編譯後就不能再修改,可是能夠添加。
● 方案1:將腳本與資源所有分離。
● 項目管理很是麻煩。
● 動態掛載全部腳本。
● 沒法在編輯器中使用動態編輯。
● 方案2:將接口與實現分離。
● 不改變用戶工做流程。
● 仍可在編輯器重使用動態編輯。
● 對代碼起到必定的保護做用(能夠混淆)。
● 對原有的AssetBundles打包方案沒有任何影響。