Unity在场景切换之间清理下内存
发表于2016-05-28
看了两篇关于Unity加载和内存管理的文章,写得很详细。
文章链接:
http://game.ceeger.com/forum/read.php?tid=4394
http://game.ceeger.com/forum/read.php?tid=4466
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | using System; using UnityEngine; using System.Collections; using System.Runtime.CompilerServices; using Object = UnityEngine.Object; public class ClearSceneData : MonoBehaviour { //异步对象 private AsyncOperation async; //下一个场景的名称 private static string nextSceneName; void Awake() { Object[] objAry = Resources.FindObjectsOfTypeAll for ( int i = 0; i < objAry.Length; ++i) { objAry[i] = null ; //解除资源的引用 } Object[] objAry2 = Resources.FindObjectsOfTypeAll for ( int i = 0; i < objAry2.Length; ++i) { objAry2[i] = null ; } //卸载没有被引用的资源 Resources.UnloadUnusedAssets(); //立即进行垃圾回收 GC.Collect(); GC.WaitForPendingFinalizers(); //挂起当前线程,直到处理终结器队列的线程清空该队列为止 GC.Collect(); } void Start() { StartCoroutine( "AsyncLoadScene" , nextSceneName); } ///
/// 静态方法,直接切换到ClearScene,此脚本是挂在ClearScene场景下的,就会实例化,执行资源回收 /// /// public static void LoadLevel( string _nextSceneName) { nextSceneName = _nextSceneName; Application.LoadLevel( "ClearScene" ); } ///
/// 异步加载下一个场景 /// /// /// IEnumerator AsyncLoadScene( string sceneName) { async = Application.LoadLevelAsync(sceneName); yield return async; } void OnDestroy() { async = null ; } }
|