assetbundle能不能删除_Addressable基础篇之AssetBundle最佳实践

cac0427ec398654b62ab6205056acdb1.png

这是侑虎科技第672篇文章,感谢作者放牛的星星供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:793972859)

作者主页:https://www.zhihu.com/people/niuxingxing,作者也是U Sparkle活动参与者,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩!


本篇是Addressable基础篇系列第四节,上一节我们介绍了AssetBundle的基础原理,并且讲解了从加载AssetBundle到加载Asset的各种过程,以及底层API实现等细节内容,这一节,我们会讨论在实际使用AssetBundles的过程中遇到的问题以及解决方案。

一、管理已经加载的Assets

在一些内存敏感的环境中,严格控制加载对象的大小和数量是至关重要的。当对象从活动场景中被移除时,Unity并不会自动卸载对象。Assets的清理工作是在特定时间触发的,当然也可以手动触发(其实就是GC了)。

AssetBundle必须要小心管理。在本地存储(通过Unity缓存或通过AssetBundle.LoadFromFile加载的文件)里的文件支持的AssetBundle具有最小的内存开销,很少超过几十K字节。但是,如果存在大量的AssetBundles,这种开销仍然会成为问题。

由于大多数项目允许用户重复体验游戏内容(例如重新打一个关卡),因此了解何时加载或卸载AssetBundle就变得非常重要。如果AssetBundle卸载不当,则会导致内存中的对象产生冗余副本。而在某些情况下,不适当地卸载AssetBundles也会导致不良行为,例如纹理丢失。

在管理Asset和AssetBundle时,最重要的一点是调用AssetBundle.unload时的方式,unload参数为true或false。

此API将卸载正在调用的AssetBundle的包头信息。unload参数决定是否也卸载从此AssetBundle实例化的所有对象。如果设置为true,那么从AssetBundle创建的所有对象也将立即卸载,即使它们目前正在活动场景中被引用。

举个例子,假设Material M是从AssetBundle AB加载的,并且假设M当前在活动场景中。

34d6da63c3670b962509929f05c956a1.png

如果调用了AssetBundle.Unload(True),则M将从场景中移除,销毁并卸载。但是,如果调用AssetBundle.Unload(False),则AB的包头信息将被卸载,但M将保持在场景中,并且仍然是可用的。调用AssetBundle.Unload(False)破坏了M和AB之间的链接。如果AB稍后再次加载,则AB中包含的对象的新副本将会被加载到内存中。

274ec6242c71076030d7967a54e352b3.png

如果AB稍后再次加载,将会重新加载AssetBundle的头信息的新副本。然而,M不是从这个新的AB拷贝加载的。Unity并没有在AB和M的新副本之间建立任何联系。

36c7e1e7ccc32e19b91eaff13b573fd2.png

如果调用AssetBundle.LoadAsset()来重新加载M,Unity不会将旧的M副本作为AB中数据的实例。因此,Unity将加载一个新的副本的M,所以此时将会有两个相同的副本M在现场。

8a5bf8183f0cfe7c04268f158e1a2077.png

对于大多数项目来说,这样的结果是不可取的。大多数项目应该使用AssetBundle.Unload(True),并采用一种方法来确保对象不被复制。两种常见的方法是:

(1)在应用程序的生命周期内定义一个合适的节点,并在此期间卸载不需要的AssetBundle,例如在关卡切换或加载屏幕期间。这是最简单和最常见的选择。

(2)维护单个对象的引用计数,并仅当所有组成对象都未使用时才卸载AssetBundles。这允许应用程序在不重复内存的情况下卸载和重新加载单个对象。

如果应用程序必须使用AssetBundle.Unload(False),那么只能通过两种方式卸载各个对象:

(1)在场景和代码中消除对不需要的对象的所有引用。完成后,调用Resources.UnusedAsset。

(2)非附加加载场景。这将销毁当前场景中的所有对象并调用Resources.UnusedAsset。

如果项目有明确定义的节点,玩家可以等待对象加载和卸载,例如在游戏模式或关卡之间切换,则可以根据需要,卸载尽可能多的对象和加载新对象。

最简单的方法是将项目的离散块打包到场景中,然后将这些场景与所有依赖项一起构建到AssetBundles中。应用程序可以切换到“loading”场景,从而完全卸载包含旧场景的AssetBundles,然后加载包含新场景的AssetBundles。

虽然这是最简单的流程,但却需要很复杂的AssetBundles管理。由于每个项目是不同的,Unity尚没有提供通用的AssetBundles设计模式。

在决定如何将对象分组到AssetBundles时,如果必须同时加载或更新对象,则通常最好将对象捆绑到AssetBundles中。例如,考虑一个角色扮演游戏。个别的地图和裁剪场景可以按场景分组成AssetBundles,但有些对象可能会存在于很多其它场景则不能划分进去。

AssetBundles可以用来提供肖像画,游戏中的UI,以及不同的角色模型和纹理。这些稍后需要的Objects和Assets可以分组到第二组AssetBundles中,这些Assets在启动时加载,并在应用程序的生命周期内保持加载状态。

另一个问题可能会出现,如果Unity必须在AssetBundle卸载后从AssetBundle中重新加载一个对象。在这种情况下,重新加载将失败ÿ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值