【Unity】AssetBundle的加载与卸载方式摘要

AssetBundle的加载与卸载方式摘要

文中Object和Asset两个词用的比较混乱,但是Unity的官方英文文档里就是不停地在用这两个词,所以这里也没有替换为中文。


用于加载AssetBundle的API

  • AssetBundle.LoadFromFile[Async]()
    • 首选方法(在速度、磁盘使用和内存占用方面都很高效)
    • 适用于从本地存储加载未压缩或LZ4压缩的AssetBundle
    • 使用LZMA压缩的AssetBundle会被解压到内存中
    • 使用LZ4压缩或未压缩的AssetBundle会直接从磁盘读取
  • AssetBundle.LoadFromStream[Async]()
    • 适用于从流式数据中加载AssetBundle
    • 使用LZMA压缩的AssetBundle会被解压到内存中
    • 使用LZ4压缩或未压缩的AssetBundle会直接从流数据中读取
    • 加载过程中不能Dispose流式对象
  • UnityWebRequest[AssetBundle].GetAssetBundle()
    • 适用于从远程下载AssetBundle
    • 能够缓存已下载的AssetBundle以便重用
    • 缓存系统中的AssetBundle仅以文件名进行标识而不是使用URL
  • AssetBundle.LoadFromMemory[Async]()
    • 不推荐使用
    • 会产生AssetBundle的冗余副本

方括号[]用来表示类或方法的其他版本,下同。


用于从AssetBundle中加载Asset的API

  • AssetBundle.LoadAsset[Async]()
    • 首选方法
    • 适用于加载AssetBundle中的单个Object
    • 当要加载AssetBundle中超过66%的Object时,考虑使用LoadAllAssets()方法
  • AssetBundle.LoadAllAssets[Async]()
    • 适用于一次性加载AssetBundle中的全部Object
    • 比多次调用LoadAsset()更快
  • AssetBundle.LoadAssetWithSubAssets[Async]()
    • 适用于从AssetBundle中加载含有多个嵌套Object的复合Asset
    • 如果要加载的Object都来自于同一Asset并且他们和很多不相关的其他Object放在同一AssetBundle内,那么应该使用此方法

当Object被加载完成后,会调用它的Awake()方法,并在下一帧对Unity引擎可用。


用于查询AssetBundle依赖的API

  • AssetBundleManifest.GetAllDependencies()
    • 返回被AssetBundle所直接和间接依赖的所有AssetBundle的名称
  • AssetBundleManifest.GetDirectDependencies()
    • 返回被AssetBundle所直接依赖的AssetBundle的名称

加载AssetBundle时不能自动加载该AssetBundle所依赖的其他AssetBundle,但从AssetBundle中加载Asset时能够自动加载该Asset所依赖的其他Asset。

AssetBundle和其所依赖的AssetBundle的加载顺序并不重要,只要在从其中加载Asset时保证被依赖的AssetBundle已经加载即可。


用于卸载AssetBundle的API

  • AssetBundle.Unload()
    • 卸载此AssetBundle
    • 如果参数unloadAllLoadedObjects传入false
      • 此AssetBundle中的Asset的压缩数据文件将被卸载
      • 无法再从此AssetBundle中加载任何Object
      • 已经从此AssetBundle中加载的Object仍能正常工作
    • 如果参数unloadAllLoadedObjects传入true
      • 首选方式
      • 所有从此AssetBundle中加载的Object都将被销毁
      • Scene中对这些Object的引用将会丢失
  • AssetBundle.UnloadAllAssetBundles()
    • 卸载当前已加载的所有AssetBundle
    • 参数作用与AssetBundle.Unload()方法的参数相同
  • Resources.UnloadUnusedAssets()
    • 卸载所有未被使用的Asset

Asset的清理会在特定时期触发,但也可以手动触发。

当从AssetBundle中加载的Object被从活动的Scene中移除时,Unity不会自动将其卸载。

卸载AssetBundle但不卸载从其中加载的Object将会破坏此AssetBundle与Object之间的链接关系。如果之后再次加载了此AssetBundle并加载同一Object,内存中就会产生新的Object副本,而不是使用未被卸载的那个Object。

最好将那些需要同时加载或者更新的Object打包到同一个AssetBundle中。


Asset分配策略

  • AssetBundle太少
    • 增加运行时内存占用
    • 增加加载时间
    • 需要下载的内容更大
  • AssetBundle太多
    • 增加构建时间
    • 使开发更复杂
    • 增加整体下载时间
  • 分组Object的基本策略
    • 根据逻辑实体分组
    • 根据Object类型分组
    • 根据同时使用的内容分组
  • 选择AssetBundle压缩方式时需要考虑的问题
    • 加载时间:从本地加载未压缩的AssetBundle要比加载压缩过的AssetBundle快得多
    • 构建时间:LZMA和LZ4压缩文件的速度非常慢
    • 应用大小:如果AssetBundle被附带在项目中,将它们压缩可以减小应用程序的体积
    • 内存占用:如果考虑内存占用量,请使用不压缩或者以LZ4压缩的AssetBundle
    • 下载时间:如果AssetBundle很大或者用户网络带宽有限,那可能需要压缩
    • 如果AssetBundle中的主要内容是使用紧密压缩算法进行压缩的DXT压缩纹理,那么这个AssetBundle不应该再被压缩
    • 强烈建议开发者不要在WebGL项目中使用压缩的AssetBundle

AssetBundle补丁更新

使用AssetBundle进行补丁更新只需简单的使用新AssetBundle替换已有的AssetBundle即可。如果正在使用UnityWebRequest[AssetBundle]管理应用程序的AssetBundle缓存,那么传递一个不同的version参数即可触发下载新的AssetBundle。

补丁系统需要维护两个信息列表:

  • 含有当前已下载的AssetBundle及其版本信息的列表
  • 含有服务器上的AssetBundle及其版本信息的列表

补丁系统应该下载服务器上的AssetBundle的信息,然后与本地的AssetBundle信息进行比对,重新下载缺失的和版本信息发生变化的AssetBundle。

你可能感兴趣的:(Unity)