https://blog.csdn.net/qq_33337811/article/details/73849019 转载

Unity5的AssetBundle管理(加载、卸载)

一、获取AssetBundle对象的常用API:

 1.先获取WWW对象,再通过WWW.assetbundle获取AssetBundle对象:
 // -1-WWW www = new WWW(string url);
 加载Bundle文件并获取WWW对象,完成后会在内存中创建较大的WebStream(解压后的内容,通常为原Bundle文件的4-5倍大小,纹理资源比例可能更大),因此后续的AssetBundle.Load(5.3后为AssetBundle.LoadAsset)可以直接在内存中进行。
 // -2-WWW www = WWW.LoadFromCacheOrDownLoad(string url,int version,uint crc=0);
 加载Bundle文件并获取WWW对象,同时将解压形式的Bundle内容存入磁盘作为缓存(若该Bundle已经在缓存中,则省去这一步),完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load(5.3后为AssetBundle.LoadAsset)需要通过IO从磁盘中的缓存获取。
 public AssetBundle assetBundle;//通过之前两个接口获取WWW对象后,即可通过WWW.assetBundle获取AssetBundle对象。

2.直接获取AssetBundle:

 // -1- 从文件中读取AB//5-5.3public static AssetBundle CreateFromFile(string path);  //不支持压缩//通过未压缩的Bundle文件,同步创建AssetBundle对象,这是最快的创建方式。//(CreateFromFile因为不支持压缩,所以只能读取未压缩的路径和资源或者用WWW去读)//创建完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load需要通过IO从磁盘中获取。//5.3以后为 public static AssetBundle LoadFromFile(string path,uint crc = 0, ulong offset = 0)   //支持任意压缩格式//crc:可选的未压缩内容的CRC-32校验和,若不为0则内容加载之前要和校验和比较,不匹配则报错//offset:可选的字节偏移。这个值指定从哪里开始读取AssetBundle。//LZMA压缩:数据会解压到内存;未压缩和LZ4(块)压缩:直接从磁盘读取资源包,不会有额外的内存开销的。// -2- 从字节数组中读取AB//5-5.3public static AssetBundleCreateRequest CreateFromMemory(byte[] binary);//通过Bundle的二进制数据,异步创建AssetBundle对象,完成后会在内存中创建较大的WebStream。//调用时,Bundle的解压是异步进行的,因此对于未压缩的Bundle文件,该接口与CreateFromMemoryImmediate等价。//5.3以后为 public static AssetBundleCreateRequest LoadFromMemoryAsync(byte[] binary,uint crc = 0);//当你用WWW去下载一个加密的数据,然后需要用解密后的bytes去创建AB时这个很好用。//与同步方法相比,这个会在后台线程解压AB,不会立即创建AB。//加载完成用assetBundle属性去获取AB// -3-public static AssetBundle CreateFromMemoryImmediate(byte[] binary);//5.3以后:LoadFromMemory  该接口是上条从字节数组加载AB的同步版本。
 注:5.3下分别改名为LoadFromFile,LoadFromMemory,LoadFromMemoryAsync并增加了LoadFromFileAsync,且机制也有一定的变化,可详见Unity官方文档。

这几种方法内存消耗和性能比较:(Unity5.4)


注意:当使用WWW来下载一个bundle时,WebRequest还会有一个8*64KB的缓存区用来存储来自socket的数据。

二、从AssetBundle加载资源的常用API:

 // -1- 5.0-5.3public Object Load(string name, Type type);//通过给定的名字和资源类型,加载资源。加载时会自动加载其依赖的资源,即Load一个Prefab时,会自动Load其引用的Texture资源;//多个资源打到一个AB上时,根据名称及后缀去加载指定资源。//5.3以后 为 public Object LoadAsset(string name);//两个资源打到一个AB上时,根据名称及后缀去加载指定的资源//注:LoadAsset可以根据名称加载资源,但是有些资源没有设置ABName但是被依赖了然后也被打进AB中//这类资源无法通过Load及LoadAll返回获取到(LoadAll虽然会加载但返回的数组中不含它们)。// -2- 5.0-5.3public Object[] LoadAll(Type type);//一次性加载Bundle中给定资源类型的所有资源。// 5.3以后public Object[] LoadAllAssets(Type type);// -3- 5.0-5.3public AssetBundleRequest LoadAsync(string name, Type type);//该接口是Load的异步版本。// 5.3以后public AssetBundleRequest LoadAssetAsync(string name);注:5.x下分别改名为LoadAsset,LoadAllAssets,LoadAssetAsync,并增加了LoadAllAssetsAsync。

三、AssetBundle加载接口对比:

 1.new WWW与WWW.LoadFromCacheOrDownload前者优势:-后续的Load操作在内存中进行,相比后者的IO操作开销更小;-不形成缓存文件,而后者则需要额外的磁盘空间存放缓存;-能通过WWW.texture,WWW.bytes,WWW.audioClip等接口直接加载外部资源,而后者只能用于加载AssetBundle前者劣势:-每次加载都涉及到解压操作,而后者在第二次加载时就省去了解压的开销;-在内存中会有较大的WebStream,而后者在内存中只有通常较小的SerializedFile。(此项为一般情况,但并不绝  对,对于序列化信息较多的Prefab,很可能出现SerializedFile比WebStream更大的情况)

四、内存分析

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418145004305.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L20wXzQ2MTg0Nzk1,size_16,color_FFFFFF,t_70)在管理AssetBundle时,了解其加载过程中对内存的影响意义重大。在上图中,我们在中间列出了AssetBundle加载资源后,内存中各类物件的分布图,在左侧则列出了每一类内存的产生所涉及到的加载API:-WWW对象:在第一步的方式1中产生,内存开销小;-WebStream:在使用new WWW或CreateFromMemory时产生,内存开销通常较大;-SerializedFile:在第一步中两种方式都会产生,内存开销通常较小;-AssetBundle对象:在第一步中两种方式都会产生,内存开销小;-资源(包括Prefab):在第二步中通过Load产生,根据资源类型,内存开销各有大小;-场景物件(GameObject):在第二步中通过Instantiate产生,内存开销通常较小。-在后续的章节中,我们还将针对该图中各类内存物件分析其卸载的方式,从而避免内存残留甚至泄露。

五、注意点

1.Unity5.4之前:
CreateFromFile只能适用于未压缩的AssetBundle,而Android系统下StreamingAssets是在压缩目录(.jar)中,
因此需要先将未压缩的AssetBundle放到SD卡中才能对其使用CreateFromFile;WWW接口可以加载压缩的AB。Unity5.4之后的LoadFromFile支持任意压缩格式的AB,所以没有太大必要使用WWW了,而且这个接口像
WWW.LoadFromCacheOrDownload接口一样,加载不压缩或者LZ4压缩格式的AB的时候是不会有额外的内存开销的。2.iOS系统有256个开启文件的上限,因此,内存中通过CreateFromFile或WWW.LoadFromCacheOrDownload加载的
AssetBundle对象也会低于该值,在较新的版本中,如果LoadFromCacheOrDownload超过上限,则会自动
改为new WWW的形式加载,而较早的版本中则会加载失败。3.CreateFromFile和WWW.LoadFromCacheOrDownload的调用会增加RersistentManager.Remapper的大小,而
PersistentManager负责维护资源的持久化存储,Remapper保存的是加载到内存的资源HeapID与源数据FileID的
映射关系,它是一个Memory Pool,其行为类似Mono堆内存,只增不减,因此需要对这两个接口的使用做合理的规划。4.对于存在依赖关系的Bundle包,在加载时主要注意顺序。举例来说,假设CanvasA在BundleA中,所依赖的AtlasB
在BundleB中,为了确保资源正确引用,那么最晚创建BundleB的AssetBundle对象的时间点是在实例化CanvasA之前。
即,创建BundleA的AssetBundle对象时、Load(“CanvasA”)时,BundleB的AssetBundle对象都可以不在内存中。

 根据经验,建议AssetBundle文件的大小不超过1MB,因为在普遍情况下Bundle的加载时间与其大小并非呈线性关系,过大的Bundle可能引起较大的加载开销。由于WWW对象的加载是异步的,因此逐个加载容易出现下图中CPU空闲的情况(选中帧处Vsync占了大部分),此时建议适当地同时加载多个对象,以增加CPU的使用率,同时加快加载的完成。

六、AB卸载

前文提到了通过AssetBundle加载资源时的内存分配情况,下面,我们结合常用的API来介绍如何将已分配的内存
进行卸载,最终达到清空所有相关内存的目的。

1.内存分析

在上图中的右侧,我们列出了各种内存物件的卸载方式:场景物件(GameObject):这类物件可通过Destroy函数进行卸载;
资源(包括Prefab):除了Prefab以外,资源文件可以通过三种方式来卸载:
1) 通过Resources.UnloadAsset卸载指定的资源,CPU开销小;
2)通过Resources.UnloadUnusedAssets一次性卸载所有未被引用的资源,CPU开销大;
3)通过AssetBundle.Unload(true)在卸载AssetBundle对象时,将加载出来的资源一起卸载。WWW对象:调用对象的Dispose函数或将其置为null即可;WebStream:在卸载WWW对象以及对应的AssetBundle对象后,这部分内存即会被引擎自动卸载;SerializedFile:卸载AssetBundle后,这部分内存会被引擎自动卸载;AssetBundle对象:AssetBundle的卸载有两种方式:
1)通过AssetBundle.Unload(false),卸载AssetBundle对象时保留内存中已加载的资源;
2)通过AssetBundle.Unload(true),卸载AssetBundle对象时卸载内存中已加载的资源,由于该方法容易引起资源
引用丢失,因此并不建议经常使用;

2.注意点

 在通过AssetBundle.Unload(false)卸载AssetBundle对象后,如果重新创建该对象并加载之前加载过的资源到内存时,会出现冗余,即两份相同的资源。被脚本的静态变量引用的资源,在调用Resources.UnloadUnusedAssets时,并不会被卸载,在Profiler中能够看到其引用情况。

七、针对项目的建议

 由于以上分析的几种加载手段各有各的使用情景和特点。因此建议在我们的项目中按照以下情景使用这些方法:1、 随游戏一同发布的AssetBundle(一般位于StreamingAssets文件夹中):在打AssetBundle包时,使用LZ4压缩格式进行打包(开启BuildAssetBundleOptions.ChunkBasedCompression即可)。在运行时需要加载AssetBundle对象时,使用LoadFromFile方法进行加载。这样做的好处是:即可以将AssetBundle文件压缩,又可以兼顾加载速度,且节约内存。2、作为更新包,需要从服务端下载的AssetBundle:在打AssetBundle包时,使用默认的LZMA格式压缩。使用WWW.LoadFromCacheOrDownload方法下载并缓存AssetBundle包文件。这样做的好处是:获得了最大的压缩率,在下载过程中可以减少数据传输量。同时,在本地磁盘创建缓存之后,又可以兼顾之后的加载速度,且节约内存。3、我们自己进行加密的AssetBundle:在打AssetBundle包时,使用LZ4压缩格式进行打包(开启BuildAssetBundleOptions.ChunkBasedCompression即可)。在运行时需要加载AssetBundle对象时,使用LoadFromMemory方法进行加载。(这也是从内存中使用流数据加载AssetBundle对象的仅有的使用场景。)4、我们自己压缩的AssetBundle:我们自己也可以使用第三方库或工具对生成的AssetBundle包文件进行压缩,如果需要这样做,则我们最好不要再使用Unity3D对AssetBundle进行压缩,因此在打包时选择开启BuildAssetBundleOptions.UncompressedAssetBundle。在运行时需要加载AssetBundle对象时,使用LoadFromFileAsync方法进行异步加载

八、UWA的建议:

 1/ 对于需要常驻内存的Bundle文件来说,优先考虑减小内存占用,因此对于存放非Prefab资源(特别是纹理)的Bundle文件,可以考虑使用WWW.LoadFromCacheOrDownload或AssetBundle.CreateFromFile加载,从而避免WebStream常驻内存;2/ 而对于存放较多Prefab资源的Bundle,则考虑使用new WWW加载,因为这类Bundle用WWW.LoadFromCacheOrDownload加载时产生的SerializedFile可能会比new WWW产生的WebStream更大。3/ 对于加载完后即卸载的Bundle文件,则分两种情况:优先考虑速度(加载场景时)和优先考虑流畅度(游戏进行时)。1)加载场景的情况下,需要注意的是避免WWW对象的逐个加载导致的CPU空闲,可以考虑使用加载速度较快的WWW.LoadFromCacheOrDownload或AssetBundle.CreateFromFile,但需要避免后续大量地进行Load资源的操作,引起IO开销(可以尝试直接LoadAll)。2) 游戏进行的情况下,则需要避免使用同步操作引起卡顿,因此可以考虑使用new WWW配合AssetBundle.LoadAsync来进行平滑的资源加载,但需要注意的是,对于Shader、较大的Texture等资源,其初始化操作通常很耗时,容易引起卡顿,因此建议将这类资源在加载场景时进行预加载。只在Bundle需要加密的情况下,考虑使用CreateFromMemory,因为该接口加载速度较慢。尽量避免在游戏进行中调用Resources.UnloadUnusedAssets(),因为该接口开销较大,容易引起卡顿,可尝试使用Resources.Unload(obj)来逐个进行卸载,以保证游戏的流畅度。

AssetBundle加载和卸载相关推荐

  1. U3D assetbundle加载与卸载的深入理解

    U3D assetbundle加载与卸载的深入理解 using UnityEngine; using System.Collections; using System;public class tes ...

  2. 正确使用AssetBundle加载和卸载

    在使用Unity开发项目时,AssetBundle是必须使用的,对资源进行打包加载,因为移动端游戏包体的大小对用户体验非常重要,对内存的使用更加重要,下面我们就介绍一下关于AssetBundlle的使 ...

  3. Unity中的三种资源加载和卸载

    前言 内容转载自: https://www.cnblogs.com/zhoujiangyue/articles/7066070.html. Unity中三种资源加载方式: 1.静态引用.具体操作:创建 ...

  4. 通过应用程序域AppDomain加载和卸载程序集之后,如何再返回原来的主程序域

    实现目的:动态加载dll,执行完毕之后可以随时卸载掉,并可以替换这些dll,以在运行中更新dll中的类. 其实就是通过应用程序域AppDomain加载和卸载程序集. 在这方面微软有篇文章http:// ...

  5. 关于unity 中使用AssetBundle加载资源,shader偶尔会丢失的问题解决办法

    问题描述: 因为项目中要进行热更新设计,所以用unity官方推荐的打包方式assetbundle进行打包,打包好了以后再电脑上运行正常,但是当发布到android上后发现偶尔场景背景会出现空白,多方查 ...

  6. C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件。...

    原文:C#.Net 如何动态加载与卸载程序集(.dll或者.exe)6-----在不卸载程序域的前提下替换程序集文件. 当某个程序集文件被载入AppDomain,该文件在AppDomain.Unloa ...

  7. C#中动态加载和卸载DLL

    在C++中加载和卸载DLL是一件很容易的事,LoadLibrary和FreeLibrary让你能够轻易的在程序中加载DLL,然后在任何地方卸载.在C#中我们也能使用Assembly.LoadFile实 ...

  8. U3D assetbundle加载

    U3D assetbundle加载 1 using UnityEngine; 2 using System.Collections; 3 public class testLoadFromAB : M ...

  9. C# 动态加载 动态卸载

    代码 using System; using System.Collections.Generic; using System.Text; using System.Threading; using  ...

最新文章

  1. win10修改mac地址
  2. Linux 终端下颜色的输出
  3. 公司禁用U盘和移动硬盘的方法
  4. 【阿里云课程】图像翻译GAN结构与应用
  5. angularjs与server交互
  6. ptrace和wait的理解 (ptrace监控进程)
  7. linux下ffmpeg安装
  8. 【POJ - 1696】Space Ant (凸包,最小极角,排序)
  9. gaf处理一维故障信号_【推荐文章】改进局部均值分解的齿轮箱复合故障特征提取...
  10. 2020-python小工能
  11. ES6学习(新增字符串方法)
  12. python原理及代码_lightgbm原理以及Python代码
  13. 自考----怎么说我不爱你
  14. 清华同方计算机教程,清华同方电脑u盘重装系统win10教程
  15. windows dll 学习
  16. Hadoop安装部署
  17. 最历害的硬盘修复工具PC3000,可重置SMART状态!
  18. yolov5环境配置及训练coco128数据集
  19. Base64系列第一篇 Base64介绍
  20. 一生践行“心正则字正”

热门文章

  1. [MATLAB]基本操作与矩阵输入
  2. 高效备考CISAW认证考试
  3. 解决 React的 typeerror: Cannot add property updater, object is not extensible
  4. 从头开始制作51智能车——循迹+遥控+避障
  5. vivo计算机背景,怎么修改VIVO手机浏览器中的主题与背景颜色
  6. 焦耳小偷工作原理分析
  7. IDEA导出jar包并使用exe4j制作可执行文件
  8. pyqt(一)pyqt环境搭建 win+mac(pycharm+designer)
  9. CSS属性详解——使用border属性设置边框
  10. 【牛客网】牛客寒假算法基础集训营2——处女座与重修费