Unity资源加载与释放

时间:2024-03-28 16:13:03

部分转自:https://www.cnblogs.com/liudq/p/5550273.html

AssetBundle 与 Resources的区别
Resources相当于Unity一个缺省的AssetBundle。
AssetBundle可以在使用时动态加载。
Resources.load();在没有第一次Instantiate之前没有完全加载Asset资源。所以相对AssetBundle去实例一个资源,Resources会在第一次Instantiate时出现卡顿现象。

AssetBundle 加载与释放
AssetBundle的加载方式有:AssetBundle.LoadFromFile(“”); AssetBundle.LoadFromMemorty(byte[]);及WWW方式。
AssetBunddle.LoadFromFile(“”);只有在standalone上可以使用。WWW在加载AssetBundle时,会在内部创建assetBundle实例。
当AssetBundle被加载到内存后,其实内存中只有AssetBundle文件的镜像内存。//todo 该镜像文件是AssetBundle原文件大小?
当需要具体某个Prefab等资源时,使用assetbundle.Load(“”);加载具体资源。此时内存中会存在此资源的 GameObject、shaders、材质、贴图等内存。当具体Instantiate一个资源时,会对此资源的Asset资源进行clone+引用操作。Clone的资源包括GameObject、Tranform。引用的资源包括Texture、TerrainData、Shader。引用与Clone同时存在的包括 Mesh、material、PhysicMaterial、noxss。引用的资源只是指针的指向。Clone的会重新生成新的内存。
根据AssetBundle资源的加载方式,当资源释放时,如果只是Destroy,只会释放生成这个资源时Clone的那部分内存。assetBundle.Load(“”);加载的Asset内存没有被释放,AssetBundle的镜像内存也没有被释放。所以如果在该资源被销毁时需要使用Resources.UnloadUnuseAssets();去释放没有被使用的Asset资源内存。如果该AssetBundle不会被再使用可以使用AssetBundle.Unload(true)销毁内存。AssetBundle(true);代表销毁该AssetBundle镜像内存及所加载的Asset内存。参数为false时,代表只销毁镜像内存。
下面的图片可以更形象的理解AssetBundle的加载与释放。
Unity资源加载与释放

备注
当场景在切换时,Unity 会自动 把托管的内存释放,这其中包括Asset内存、Instantiate内存。但不会被释放的是AssetBundle镜像内存。
assetBundle.Load如果多次加载相同的资源,除第一次,其它都会返回第一次的对象。

常用方式

(1)通过www或file进来的 assetbundle可以在实例化之后,卸载。 如下代码为加载场景的

		using (WWW www = new WWW(url))
        {
            yield return www;

            var bd = www.assetBundle;
			 if(www.isDone)
			 {
			     SceneManager.LoadScene("2");
                www.assetBundle.Unload(false); //只卸载镜像即可
			 }
			 else
			 {
			     Debug.Log(www.error);
			 }
           
        }

实例化的内容可不必纠结,在切换场景时,unity会自动销毁。

问题记录
在通过www加载场景多次时,有时有报出“No cameras rendering”,并输出“PreloadData is missing. It should always be there”.
暂分析的是应该是加载场景未完全完成时,卸载资源就调用。
可以用一下方法解决:

	    using (WWW www = new WWW(url))
        {
            yield return www;

            var bd = www.assetBundle;
            if(www.error!=null)
            {
                Debug.Log(www.error);
                yield return false;
            }
            if(www.isDone)
            {
                AsyncOperation ao = SceneManager.LoadSceneAsync("2",LoadSceneMode.Single);
                yield return ao ; //保证加载完成再调用卸载
                
                www.assetBundle.Unload(false); 
            }

        }

另外,这个脚本赋予的对象设置成场景切换不销毁即可

DontDestroyOnLoad(this);