【AssetBundle 平台差异问题反馈】两个优先级相同的Bundle依赖同一个资源,web平台只有一个 bundle能获取到 assetInfo

  • Creator 版本: 3.8.2

  • 目标平台: Android / Web(IDE调试模式)

  • 重现方式:
    1.有两个 bundle: bundleA 和 bundleB
    2.bundleA 依赖 bundleB里的资源 x.png,因为两个 bundle 优先级相同,所以两个 bundle构建会各打一份资源
    3.但是通过 bundleA.getAssetInfo(x的uuid), Web平台获取为null,安卓平台正常可以取到,按道理两个 bundle 都应该能获取到?哪个平台表现正常呢

另外安卓平台问题:卸载释放 bundleA 会导致 bundleB 的 x 图片也被释放,两个 bundle 各自打了一份资源,正常理解是只可以释放 bundleA 的资源,但是资源又不跟 bundle 走,是全局缓存在assetManager,因为是相同的 uuid,所以导致 bundleB 存在但是资源 x 被释放。这是设计如此吗?如果设计这样那开发者就得很注意资源的释放,要关心 bundle 间有无相同资源引用。

这就导致我查很久关于资源释放的问题- -!

@111304 @50353438 请大佬帮忙看看

你这种打包方式策略不太对,依赖资源要么放入A中,要么当做公共依赖资源放入公共依赖包C中。当然我不知道你这个B是另一个预制体资源还是公共依赖资源。

加载资源A的时候,依赖资源被加载的同时,将资源A和依赖资源一起存入字典对象池。资源卸载的时候,把对象池字典A的引用置空然后再删除A键值对,然后删除场景对象A,B或者C不动。

当再次加载A时,你的自定义加载方法会先在加载的时候检查对象池中A的依赖资源是否被加载了,如果已经加载过依赖资源了,就跳过这次依赖加载进行下一个A资源依赖加载。当你再次加载完A时,直接实例化A重复之前的动作。

不是我自己的策略,虽然可以把两个 bundle 依赖的资源提取到公共包,但实际开发很难管理资源依赖关系,况且官方是支持这种打包情况的,请看文档:Asset Bundle 介绍 | Cocos Creator
我的情况可以说和文档提到的情况一模一样:

我也理解你说的,但实际上帖子重点不是打包策略,而是平台差异问题

ide 调试还没有打包所以 x.png 还只在bundleB中, 这不是平台差异,文档说的一切都是打包之后的

1赞

那这个点没问题了。
请教下第2个疑问,因为资源不跟 bundle 走,这种依赖关系在资源释放时就只能开发者自己避免咯?要么不卸载,要么把资源再提取到另一个公共 bundle

不用想那么复杂,如果预制体加资源都很小,且资源共享的不多或者没有,那么1个预制体资源 对应 1个资源包足以,这是小包模式。

如果有多个预制体依赖相同资源,将相同依赖资源打进同1个资源包,预制体本身不大可以打进同个资源包。最终打出很多共享的大资源包,这是大包模式。

加载的时候,先检查对象池是否已经存储本次加载的任意资源并且不为空,缺哪个补哪个。加载完实例化预制体。

卸载的时候,对象池置空对应键值对并且删除键值对。节点销毁。不需要你手动释放。

下次加载的时候,按照同样的步骤加载。同时注意加载的时候,如果是异步加载注意对象池竞争和资源加载竞争问题,并且禁止同时异步2个资源(都依赖相同的资源)加载。而是,先异步一个资源,然后在回调函数中,异步或者同步加载另一个资源(一般在回调里面同步加载即可)

十分感谢提供思路

这个我碰到过,我卸载一个模块包的时候,连带其他资源包里面复制的资源都会卸掉。
我的办法是改引擎代码,卸载的时候,对资源进行检测,有没有多个bundle里面有,如果有,就不卸载。真正到最后一个bundle引用的时候才卸载。

这里的修改,还牵涉到不删除bundle外的资源,例如一个模块bundle,卸载的时候资源引用到了公共bundle,连带着对公共包内的对应依赖资源,会执行卸载操作。

谨慎修改,这个卸载方案是和我们卸载资源形式有关(整包卸载),靠外部引用计数来控制单独资源卸载的请谨慎使用。

1赞

对的!使用上我也认为引擎应该对资源检测看是否有别的 bundle 里面有用到(但文档是有说明 bundle 卸载不会检查依赖的),可能与引擎设计违背吧,bundle 只是记录拥有哪些资源,加载资源在 assetmanager 维护。
用引用计数控制资源释放是最佳的,bundle其实也没有必要去卸载,本身占用内存不大。所以我后面动态资源加载就自己 addRef/decRef 控制了