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