当前位置: 首页 > news >正文

AssetBundle管理机制(上)

AssetBundle内存管理机制
 
 

接上期AssetBundle打包的讲解,我们今天为大家继续探秘AssetBundle,从管理机制的角度出发,谈谈其资源加载和卸载的原理。

同时如果你恰有相关疑问,欢迎后台留言给UWA,或者加入QQ群(465082844)讨论,当然也不要忘记关注UWA哦。

 

◆◆◆◆

 AssetBundle加载基础


通过AssetBundle加载资源,分为两步,第一步是获取AssetBundle对象,第二步是通过该对象加载需要的资源。而第一步又分为两种方式,下文中将结合常用的API进行详细地描述。

 

第一步,获取AssetBundle对象的常用API


方式一,先获取WWW对象,再通过WWW.assetBundle获取AssetBundle对象:

● public WWW(string url);

加载Bundle文件并获取WWW对象,完成后会在内存中创建较大的WebStream(解压后的内容,通常为原Bundle文件的4~5倍大小,纹理资源比例可能更大),因此后续的AssetBundle.Load可以直接在内存中进行。

【厚积薄发】你应该知道的AssetBundle管理机制(上)    

 ● public static WWW LoadFromCacheOrDownload(string url, int version, uint crc = 0);

加载Bundle文件并获取WWW对象,同时将解压形式的Bundle内容存入磁盘中作为缓存(如果该Bundle已在缓存中,则省去这一步),完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load需要通过IO从磁盘中的缓存获取。

 

● public AssetBundle assetBundle;

通过之前两个接口获取WWW对象后,即可通过WWW.assetBundle获取AssetBundle对象。


方式二,直接获取AssetBundle:

● public static AssetBundle CreateFromFile(string path);

通过未压缩的Bundle文件,同步创建AssetBundle对象,这是最快的创建方式。创建完成后只会在内存中创建较小的SerializedFile,而后续的AssetBundle.Load需要通过IO从磁盘中获取。

 

● public static AssetBundleCreateRequest CreateFromMemory(byte[] binary);

通过Bundle的二进制数据,异步创建AssetBundle对象。完成后会在内存中创建较大的WebStream。调用时,Bundle的解压是异步进行的,因此对于未压缩的Bundle文件,该接口与CreateFromMemoryImmediate等价。

 

● public static AssetBundle CreateFromMemoryImmediate(byte[] binary);

该接口是CreateFromMemory的同步版本。

 

注:5.3下分别改名为LoadFromFile,LoadFromMemory,LoadFromMemoryAsync并增加了LoadFromFileAsync,且机制也有一定的变化,可详见Unity官方文档。

 

第二步,从AssetBundle加载资源的常用API

 

● public Object Load(string name, Type type);

通过给定的名字和资源类型,加载资源。加载时会自动加载其依赖的资源,即Load一个Prefab时,会自动Load其引用的Texture资源。

 

● public Object[] LoadAll(Type type);

一次性加载Bundle中给定资源类型的所有资源。

 

● public AssetBundleRequest LoadAsync(string name, Type type);

该接口是Load的异步版本。

 

注:5.x下分别改名为LoadAsset,LoadAllAssets,LoadAssetAsync,并增加了LoadAllAssetsAsync。

 

◆◆◆◆

AssetBundle加载进阶

 

接口对比:new WWW与WWW.LoadFromCacheOrDownload

 

前者的优势

●  后续的Load操作在内存中进行,相比后者的IO操作开销更小;

● 不形成缓存文件,而后者则需要额外的磁盘空间存放缓存;

● 能通过WWW.texture,WWW.bytes,WWW.audioClip等接口直接加载外部资源,而后者只能用于加载AssetBundle;

 

前者的劣势

● 每次加载都涉及到解压操作,而后者在第二次加载时就省去了解压的开销;

●  在内存中会有较大的WebStream,而后者在内存中只有通常较小的SerializedFile。(此项为一般情况,但并不绝对,对于序列化信息较多的Prefab,很可能出现SerializedFile比WebStream更大的情况)

 

内存分析

 【厚积薄发】你应该知道的AssetBundle管理机制(上) 

在管理AssetBundle时,了解其加载过程中对内存的影响意义重大。在上图中,我们在中间列出了AssetBundle加载资源后,内存中各类物件的分布图,在左侧则列出了每一类内存的产生所涉及到的加载API:

 

● WWW对象:在第一步的方式1中产生,内存开销小;

● WebStream:在使用new WWW或CreateFromMemory时产生,内存开销通常较大;

● SerializedFile:在第一步中两种方式都会产生,内存开销通常较小;

● AssetBundle对象:在第一步中两种方式都会产生,内存开销小;

● 资源(包括Prefab):在第二步中通过Load产生,根据资源类型,内存开销各有大小;

● 场景物件(GameObject):在第二步中通过Instantiate产生,内存开销通常较小。

 

在后续的章节中,我们还将针对该图中各类内存物件分析其卸载的方式,从而避免内存残留甚至泄露。

 

注意点

● CreateFromFile只能适用于未压缩的AssetBundle,而Android系统下StreamingAssets是在压缩目录(.jar)中,因此需要先将未压缩的AssetBundle放到SD卡中才能对其使用CreateFromFile。

Application.streamingAsstsPath = "jar:file://" Application.dataPath "!/assets/";

 

● iOS系统有256个开启文件的上限,因此,内存中通过CreateFromFile或WWW.LoadFromCacheOrDownload加载的AssetBundle对象也会低于该值,在较新的版本中,如果LoadFromCacheOrDownload超过上限,则会自动改为new WWW的形式加载,而较早的版本中则会加载失败。 

 

● CreateFromFile和WWW.LoadFromCacheOrDownload的调用会增加RersistentManager.Remapper的大小,而PersistentManager负责维护资源的持久化存储,Remapper保存的是加载到内存的资源HeapID与源数据FileID的映射关系,它是一个Memory Pool,其行为类似Mono堆内存,只增不减,因此需要对这两个接口的使用做合理的规划。

 

● 对于存在依赖关系的Bundle包,在加载时主要注意顺序。举例来说,假设CanvasA在BundleA中,所依赖的AtlasB在BundleB中,为了确保资源正确引用,那么最晚创建BundleB的AssetBundle对象的时间点是在实例化CanvasA之前。即,创建BundleA的AssetBundle对象时、Load(“CanvasA”)时,BundleB的AssetBundle对象都可以不在内存中。

【厚积薄发】你应该知道的AssetBundle管理机制(上) 

● 根据经验,建议AssetBundle文件的大小不超过1MB,因为在普遍情况下Bundle的加载时间与其大小并非呈线性关系,过大的Bundle可能引起较大的加载开销。

 

● 由于WWW对象的加载是异步的,因此逐个加载容易出现下图中CPU空闲的情况(选中帧处Vsync占了大部分),此时建议适当地同时加载多个对象,以增加CPU的使用率,同时加快加载的完成。

 【厚积薄发】你应该知道的AssetBundle管理机制(上) 

以上是AssetBundle资源加载部分,有加载自然有卸载,鉴于篇幅,我们将另起一篇,敬请关注!

转载于:https://www.cnblogs.com/VindyLeong/p/6834490.html

相关文章:

  • 详尽Netty(三):Channel
  • 循序渐进之Spring AOP(5) - 创建切面
  • 牛逼!阿里推出国产开源的jdk! 快来试试吧!
  • ES6 中的let 声明变量
  • 原来Java类的加载过程是这样的?
  • 淘宝数据库OceanBase SQL编译器部分 源代码阅读--生成物理查询计划
  • 聊聊jvm几种垃圾收集器
  • 搭建 webpack + React 开发环境
  • jvm垃圾回收的过程
  • 到底什么是分布式锁,进程锁,线程锁
  • 晶振參数校定
  • 这样做能让nginx新能提升10倍
  • 查看项目错误信息
  • 简单说明String类为什么是final的
  • RocketMQ启动broker提示 错误:找不到或无法加载主类
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • 【知识碎片】第三方登录弹窗效果
  • Angular Elements 及其运作原理
  • CentOS7简单部署NFS
  • DOM的那些事
  • httpie使用详解
  • java第三方包学习之lombok
  • jQuery(一)
  • JSDuck 与 AngularJS 融合技巧
  • MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇
  • Netty 框架总结「ChannelHandler 及 EventLoop」
  • React中的“虫洞”——Context
  • Redux 中间件分析
  • vue--为什么data属性必须是一个函数
  • webpack入门学习手记(二)
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 聊聊flink的BlobWriter
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 探索 JS 中的模块化
  • 我从编程教室毕业
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • 基于django的视频点播网站开发-step3-注册登录功能 ...
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • (07)Hive——窗口函数详解
  • (2015)JS ES6 必知的十个 特性
  • (pytorch进阶之路)扩散概率模型
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (转) Face-Resources
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • ***测试-HTTP方法
  • .net core 6 集成和使用 mongodb
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .Net小白的大学四年,内含面经
  • ::前边啥也没有
  • @JsonFormat与@DateTimeFormat注解的使用