看了兩篇關於Unity加載和內存管理的文章,寫得很詳細。
文章鏈接:
Unity系統在加載新場景時,所有的內存對象都會被自動銷毀,包括你用AssetBundle.Load加載的對象和Instaniate克隆的。
但是不包括AssetBundle文件自身的內存鏡像,那個必須要用Unload來釋放,用.net的術語,這種數據緩存是非托管的。
既然加載場景不會釋放AssetBundle文件自身的內存鏡像,那我們就手動釋放。
Destroy:主要用於銷毀克隆對象,也可以用於場景內的靜態物體,不會自動釋放該對象的所有引用。雖然也可以用於Asset,但是概念不一樣要小心,如果用於銷毀從文件加載的Asset對象會銷毀相應的資源文件!但是如果銷毀的Asset是Copy的或者用腳本動態生成的,只會銷毀內存對象。
AssetBundle.Unload(false):釋放AssetBundle文件內存鏡像
AssetBundle.Unload(true):釋放AssetBundle文件內存鏡像同時銷毀所有已經Load的Assets內存對象
Reources.UnloadAsset(Object):顯式的釋放已加載的Asset對象,只能卸載磁盤文件加載的Asset對象
Resources.UnloadUnusedAssets:用於釋放所有沒有引用的Asset對象
GC.Collect()強制垃圾收集器立即釋放內存 Unity的GC功能不算好,沒把握的時候就強制調用一下
場景A切換到場景B,使用同步加載Application.LoadLevel(sceneName)或者異步加載Application.LoadLevelAsync(sceneName)都可以。
我們可以在場景A和場景B之間插入一個清理內存的場景X,場景X就是一個空場景,它的主要作用是承上啟下,把場景A留下的資源清理,然在切換到場景B。
可以這個功能封裝起來。
1 using System; 2 using UnityEngine; 3 using System.Collections; 4 using System.Runtime.CompilerServices; 5 using Object = UnityEngine.Object; 6 7 public class ClearSceneData : MonoBehaviour 8 { 9 //異步對象 10 private AsyncOperation async; 11 12 //下一個場景的名稱 13 private static string nextSceneName; 14 15 void Awake() 16 { 17 Object[] objAry = Resources.FindObjectsOfTypeAll<Material>(); 18 19 for (int i = 0; i < objAry.Length; ++i) 20 { 21 objAry[i] = null;//解除資源的引用 22 } 23 24 Object[] objAry2 = Resources.FindObjectsOfTypeAll<Texture>(); 25 26 for (int i = 0; i < objAry2.Length; ++i) 27 { 28 objAry2[i] = null; 29 } 30 31 //卸載沒有被引用的資源 32 Resources.UnloadUnusedAssets(); 33 34 //立即進行垃圾回收 35 GC.Collect(); 36 GC.WaitForPendingFinalizers();//掛起當前線程,直到處理終結器隊列的線程清空該隊列為止 37 GC.Collect(); 38 39 } 40 41 void Start() 42 { 43 StartCoroutine("AsyncLoadScene", nextSceneName); 44 } 45 46 /// <summary> 47 /// 靜態方法,直接切換到ClearScene,此腳本是掛在ClearScene場景下的,就會實例化,執行資源回收 48 /// </summary> 49 /// <param name="_nextSceneName"></param> 50 public static void LoadLevel(string _nextSceneName) 51 { 52 nextSceneName = _nextSceneName; 53 Application.LoadLevel("ClearScene"); 54 } 55 56 /// <summary> 57 /// 異步加載下一個場景 58 /// </summary> 59 /// <param name="sceneName"></param> 60 /// <returns></returns> 61 IEnumerator AsyncLoadScene(string sceneName) 62 { 63 async = Application.LoadLevelAsync(sceneName); 64 yield return async; 65 } 66 67 void OnDestroy() 68 { 69 async = null; 70 } 71 72 }