看了两篇关于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 }