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