【Unity优化】资源管理系列03:AssetBundle 基本原理

定义:将一个或多个文件,按照一种归档格式,存在一个文件中,Unity可以索引并序列化其中的文件

操作:加载/卸载AB自身、加载卸载AB中某个资源

作用:在游戏安装后,继续分发和更新非代码资源

1)减小游戏包体

2)减小运行时内存压力

3)针对不同设备/平台,加载不同资源

AB结构

1)数据头:identifier、压缩类型、manifest

manifest:查找表,key是对象名,value中包含一个字节索引,定位数据段中对象位置

2)数据段:资源系列化后的原始数据

三种压缩类型

1)LZMA:所有资源的序列化数据,被压缩进同一个字节数组

2)LZ4:每个资源的序列化数据,单独被压缩为字节数据

3)不压缩:原始字节数据

压缩类型对比

1)LZMA:

优点:原始AB小

缺点:想要加载其中一个资源,需要解压整个AB;运行时占用内存大

2)LZ4(推荐):

优点:想要加载其中一个资源,只需要解压相关数据块;运行时占用内存小

缺点:原始AB大

加载AB

1)AssetBundle.LoadFromMemory

说明:不推荐,两倍AB内存占用,三倍资源内存占用

2)AssetBundle.LoadFromFile

说明:推荐,只加载数据头,之后按需加载资源

补充:在Editor模式下,异步方法会加载整个AB,会出现内存峰值;真机中没有

3)UnityWebRequest 的 DownloadHandlerAssetBundle

① 可以使用 UnityWebRequest.GetAssetBundle,也可使用 DownloadHandler

② DownloadHandler 使用工作线程,流式下载,存入固定大小buffer,然后传给临时存储或 AB cache。这些操作都有原生代码实现,不会产生堆分配。且不会额外保存下载字节数据的拷贝,减少内存占用。

③ 如果AB是LZMA压缩格式,在下载的时候会被解压缩,并以LZ4格式缓存。

④ AB下载完成后,通过 DownloadHandler 的 assetBundle 获取AB。

⑤ 如果AB之前已被加载,且在缓存中,则会立即返回,此时和 LoadFromFile 功能类似

4)WWW.LoadFromCacheOrDownload

说明:Unity5.6之前使用,已废弃

5)建议

① LoadFromFile,建议在任何可用的场景使用,无论是加载速度、硬盘占用、运行时内存占用,该API都是最高效的。

② UnityWebRequest,需要下载AB时使用;记得调用 Dispose 或 Using。

③ 如果自研下载器,需要适配 LoadFromFile 方法。

加载AB中资源

1)三种API

① LoadAsset(Async)

② LoadAllAssets(Async)

③ LoadAssetWithSubAssets(Async)

2)同步与异步对比

① 同步方法:至少比异步快一帧;缺点是在资源加载完毕前,会阻塞主线程

② 异步方法:可以在一帧内加载多个资源,不阻塞主线程

3)LoadAllAssets(Async)

适用场景:从一个AB中加载大部分资源,且这些资源相互独立。

优点:比多次调用 LoadAsset 快

AB策略:如果一个AB中,超过66%的资源需要同时加载,则建议将这部分分离出来单独打包

4)LoadAssetWithSubAssets(Async)

适用场景:当需要加载一个由多个小资源组合而成的大资源时

举例:FBX模型及其动画、精灵图集及其精灵

5)资源加载的一些细节

① 从存储中加载对象数据,发生在工作线程上。

② 多个工作线程,使得多个对象可以同时被反序列化、处理、整合。

③ 当一个对象被加载完毕,Awake方法被调用,从下一帧开始,该对象可被引擎使用。

④ 对象加载在一帧中的时间不超过 time-slice,该值由 ThreadPriority 决定。

⑤ 发起异步调用,和对象被引擎可用,这两步间至少需要一帧,因此相同条件下,同步方法要比异步方法快一帧。

6)AB依赖

① AB间的相互依赖可以通过 AssetDatabase 和 AssetBundleManifest 获取

② 在加载一个对象前,要先加载它依赖的所有AB。Unity不会帮忙自动加载,要自己实现

7)AssetBundle manifests

① 被包含在一个以父文件夹命名的AB中

② 包含了AB中对象之间的引用信息

③ manifest AB 和其他 AB 一样,可以被加载、缓存、卸载

④ 使用 GetAllAssetBundles 方法获取所有包含 AB 列表

⑤ 使用 GetAllDependencies 方法返回该AB的所有依赖

⑥ 使用 GetDirectDependencies 方法返回该AB的直接依赖

⑦ 上面两个方法都会分配 string 数组,不要在性能敏感处使用

8)建议

① 在性能敏感的代码之前,尽可能预加载需要的资源

posted @ 2020-07-21 22:34  何三思  阅读(509)  评论(0编辑  收藏  举报