Unity开发实战探讨-资源的加载释放最佳策略 (3)

首先UnloadUnusedAssets对所有需要释放资源有一个非常重要的前置条件:只有不存在任何引用关系的资源才能被该函数释放,看起来这是一个明确的要求,但由于Unity资源的相互引用关系比较隐晦繁复,想要明确的判断某一个资源不存在引用关系是有一定难度的,并且,如果一个我们想释放的资源存在任何隐性的引用关系,UnloadUnusedAssets将会无视这个资源而无任何反馈,这种情况常常会被开发人员忽略而造成内存的泄漏。

一般情况下,要明确一个资源不再被引用,首先要把所有用到该资源使用GameObject.Destroy函数进行销毁,然后要把所有引用到该资源的变量显性的设置为Null,尤其要关注的是类成员和静态变量的引用,最后调用UnloadUnusedAssets才能有效地释放这个资源。

根据实战经验来看,最佳使用UnloadUnusedAssets的时机还是在场景切换的时候,由于Unity的场景关闭会有效地销毁所有的对象和所有代码的引用,那么在场景切换,尤其是在新场景的开头UnloadUnusedAssets上一个场景的资源处理是比较稳妥的做法;而在场景运行过程中希望不断调用UnloadUnusedAssets来快速释放当前空闲资源其实是一招险棋,有欲速则不达的可能:

首先,如果大部分资源都存在引用,那么使用该函数徒劳无功。

其次,如果该资源在UnloadUnusedAssets以后又被起用,那么资源重新加载的损耗得不偿失。

最后,UnloadUnusedAssets是一个异步函数,在其执行过程中,一旦资源又被使用将会导致无法预知的后果。实际开发中发现在场景运行中反复调用UnloadUnusedAssets存在闪退的风险。

 

Resources最佳释放策略:

实例化的对象,在不再使用以后必须立刻Destroy,该清理操作不会引起资源的丢失,风险较小,要充分满足。

对于内存消耗非常巨大,并且在场景运行过程中能够明确不再使用的资源内存镜像,可以主动使用Reources.UnloadAsset进行强制释放。对于消耗不大的,等场景结束后进行统一释放是更稳妥的选择。

大部分资源建议在场景切换以后,通过Resources.UnloadUnusedAssets方法进行后置释放,必要时再加上GC.Collect。(在下一个场景的开始甚至在一个独立的换场场景中调用都是比较稳妥的选择)

全局静态变量和类成员变量引用的资源,务必先把引用设为Null值,然后再调用Reources.UnloadUnusedAssets才能正确释放。

 

AssetBundle资源加载

    AssetBundle是Unity提供的另一种资源加载方式,开发者可以把一批资源打包,然后通过网络下载或者文件加载的方式进行加载。

    介于Resources方式的资源必须一起打入游戏包体,AssetBundle方式则提供了一种更为灵活的资源加载方式,AssetBundle无需进入游戏包体,大大减少了游戏文件的体积,另外,AssetBundle允许通过网络下载,也为游戏资源的获取和升级提供了更为灵活的选择。

AssetBundle加载资源一般分3步,(下面是示例代码):

 

var bundle= AssetBundle.LoadFromFile(path);

var prefab = myLoadedAssetBundle.LoadAsset.<GameObject>("MyObject");

var obj = Instantiate(prefab);

   

    根据前面提到的资源的内存使用和以上示例代码所示,可以得知AssetBundle资源加载到最终加入游戏场景,需要存在3个对象:bundle本身,加载的资源prefab,和实例化出来的obj。这3个对象分别对应不同的内存镜像,在释放的时候需要分别考虑。

 

AssetBundle最佳加载策略:

相同内容的AssetBundle只Load一次,在其Unload之前反复加载会造成不必要的浪费和风险。

相同名称的资源用LoadAsset也只需加载一次,这个和Resources.Load基本类似。

AssetBundle资源释放

    根据AssetBundle的3级对象,我们分别说下各自的释放办法:

    实例化的obj:用GameObject.Destroy释放。

    加载的资源prefab:因为是内存镜像,也可以用Object.Destroy释放。另外Resources.UnloadUnusedAssets方法对这种资源释放也是有效的,但条件比较苛刻,prefab的父(bundle)和子(obj)都要已经被释放的情况下,加上本身引用清空,然后使用UnloadUnusedAssets才有效,所以这种办法并不十分推荐。

    加载的资源包bundle:AssetBundle.Unload方法是唯一的释放手段。这个方法有2个参数,都有一定的意义:

    参数为false的时候,仅仅把资源包内存释放,但保留任何已经加载的资源和实例化对象,这些资源和对象的释放有待后续代码完成。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzypp.html