Unity在场景切换之间清理下内存

发表于2016-05-28
评论1 9k浏览
  看了两篇关于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;
    }
     
 }

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论