1. 程式人生 > >Unity在場景切換之間清理下記憶體

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 }