一.问题

    首先,这里说明一下,我这边的GameObject有点笼统,就是表达的是游戏中的具体实例。

      

二.概念

     1)Asset是什么?

          游戏中具体的资源,像texture,mesh,material,shader,script等,实实在在的游戏项目文件夹中所需要堆放的资源。比如,var obj = Resource.Load<GameObject>("Prefabs/testItem"),这个obj就是Asset。

      2)GameObject是什么?

          var gameItem= Instantiate(obj),这个gameItem就是可以存在于游戏的实际场景中(这个比较简单,不多说了)。GameObject是游戏中实际使用的对象(就是你会在屏幕中实际看到的),是由Asset实例化后的对象。本质上其实还是Asset的衍变,是对部分Asset的引用和复制出来的新东西,其本质还是Asset。     

      3)AssetBundle是什么?

        由上述可知,我们在游戏中生成实际的物体,需要Asset。而Asset,比如一张图片,也是一个Asset,实际大小1M,游戏中这种图片很多,那就轻轻松松几百M,几个G的Asset,都是很有可能的。作为程序员,对于这种“原汁原味”拿过来肯定不行。比如我们工作中把文件什么的发给同事的时候都知道压缩一下,可以传输的过程中小一些。当然了,我们在游戏开发中使用Asset,也是需要类似的。于是,就推出了AssetBundle这一概念。当然我们推出AssetBundle,远不止压缩这一需求。但是你需要知道,主要是为了更好的传输,还有比如减少资源大小,利于网络那边的传输,方便加载。

        简而言之,AssetBundle就是为了让游戏项目中大量Asset适应实际游戏运行时而被压缩后的一种二进制文件。

三.分析

    1)Asset和GameObject的关系?

      ①复制+引用关系

      Instaniate一个Prefab(Asset),是对Asset进行clone(复制)+引用结合的过程。GameObject,transform是clone的。其他mesh/texture/material/shader等,这些都是纯引用的。引用的Asset对象不会被复制,只是一个简单的指针指向已经load的Asset对象。专门要提一下Script Asset,Unity里每个Script都是一个封闭的class定义,并没有写调用代码。光class是不会工作的。其实Unity引擎就是那个调用代码。clone一个script asset等于new一个class实例,实例才会工作 ,把它挂到Unity主线程的调用链去,class实例里的update和start才会被执行。多个物体挂同一个脚本,其实就是多个物体挂了挂了那个脚本的类的实例。在new class过程中,数据区是复制的,代码区是共享的,算是一种复制+引用关系。引用关系的话,会有一对一,一对多,多对一的关系。如下图:

      

      ②释放

        如果你Destroy(GameObject,这个是游戏中具有实例),只是释放了clone的asset,引用的asset并不会被干掉。还有因为destroy并不知道有没有被别的asset引用。但是如果你想把asset也释放,有两种方案。

        I. Resources.UnloadUnusedAssets()

          释放当前所有的没有被引用的(无用)asset,但是不能保证释放掉当前的被引用的资源(因为可能还被其他资源引用,就不会去释放了)。缺点:异步,会卡。由于Unity资源的相互引用关系比较复杂,想要明确判断某一资源不存在引用关系是有一定难度的,并且,如果我 们想要释放的资源存在隐形的引用关系,UnloadUnUsedAssets将会无视这个资源而无任何反馈。根据实战来看,最佳使用的时机是在场景切换进入新的场景后,Unity场景关闭会有效的销毁所有的对象和所有代码的引用,即在新场景开头最为稳妥。必要时加上GC.Collect().

        II.Resouce.UnLoadAsset(obj)     

          释放当前实例的所有被引用的asset(不管这个asset是否还有被引用,所以,风险很大,除非保证确定被他引用的资源没有再被其他资源引用,一般用于单独的一张纹理释放)缺点:风险太大,容易被报:UnloadAsset may only be used on individual assets and can not be used on GameObject's / Components or AssetBundles)用于释放shader,mesh,Texture等,没有被引用的。当然如果GameObject没有被引用,你也可以去释放。

         

          对于这种使用,对于资源大的且无引用的可以使用,如果资源消耗不大,可以等到场景切换,使用I中 Resources.unloadUnusedAssets方案。

        III.GameObject.DestroyImmediate(asset,true)

          代替上述方案,可以针对卸载asset(好像还可以直接使用GameObject.Destroy(asset) ,也可以直接使用。(待验证))
        IV.AssetBundle.unload(true)  !!!慎用

          这个也可以卸载asset,但是卸载的是这个assetBundle里面的所有的asset。(后面详说)

    2)AssetBundle和Asset的关系

         ①包含,依赖关系

            一个AssetBundle中可以包含一个或多个Asset。一个Asset依赖于AssetBundle。

         ②释放

          AssetBundle的释放只能通过以下两种方式释放。即使系统在加载新场景的时候所有的内存对象都会被自动销毁,包括你用AssetBundle.load加载的对象和Instaniate克隆的,但是不包括AssetBundle文件本身的内存镜像,那个必须要用Unload来释放,用.Net术语说该资源是非托管的。

            I.AssetBundle.Unload(false) 使用频率较多

              用AssetBundle.Load加载需要的asset之后应该立即使用unlaod(false),释放assetbundle文件本身的内存镜像,但不销毁该assetBundle加载过的asset对象。(尽量释放一部分内存,大多数游戏这么做)      

            II.AssetBundle.Unload(true)

              释放该assetBundle文件镜像并释放该assetBundle所有loaded的asset内存对象。(风险很大,因为一般不太能确定是否该loaded的asset是否还被其他资源引用)。           

四.实例测试

     AssetBundle和Asset 项目工程中大小分析

      ①首先,准备10个一样大小的texture(为了测试结果更加准备,每个图1.33M)

        

          texture 的原大小,即Asset本身的大小:1.33M *10 = 13.3M

      ②LZ4和LZMA打包方式案例对比      

        I.BuildAssetBundleOptions.None 打包方式,该为默认压缩,即LZMA,在使用AssetBundle之前需要解压缩。使用LAMA格式压缩的AssetBundle的包体最小

(高压缩比),但是会增加相应的解压缩时间和内存。

BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None,BuildTarget.StandaloneWindows64);

        以上述方式打包完之后 每张   texture :613K *10 = 6M

执行下面代码。(为方便数据对比,是在找不到大的texture了)

        

       使用AssetBundle.LoadFromFile 加载那10个AssetBundle之后的内存显示

        

        对比上2张图的消耗,大概消耗了13.6M的Unity内存,0.5M其他内存。因为是十张纹理,原纹理没有打包之前的大小大概是1.33m,也就是说,大概技术释放的是原Asset的大小。

        再Load其中的Asset

        

        由上图可知,申请的是Unity内存爆增100M左右,Mono的内存也相应的增加了。

        II.ChunkBasedCompression,即LZ4压缩方式,压缩比一般,压缩后的包体较大,但是解压速度快,消耗内存小。

BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.ChunkBasedCompression,BuildTarget.StandaloneWindows64);

        以上述方式打包完之后 每张texture :1110K*10=11100K,11M左右 

         再执行同上一致的Load脚本.   

      AssetBundle,Asset,GameObject 加载中的内存对比

        

      同上述步骤一致,给出LoadAssetBundle,即AssetBundle.LoadFromFile后的内存大小

         

     大概消耗2M内存。(上述LAMA方式打出的包是23.5M,相差10倍啊,果断使用这种方式,我们项目也是这种方式)  

      再给出LoadAsset之后的内存图

      

       LoadAsset之后,Unity内存,Mono内存都增加很多

        III.总结对比,I加载的时候LoadAssetBundle消耗明显大于II方式10倍(甚至不止,因为总量越大,差距就越大)。移动游戏中的内存多么珍贵大家懂得。使用ChunkBasedCompression,即LZ4压缩,更为划算。因为宁愿牺牲一点包体大小,也要消耗内存小一些。(我们游戏项目是这个需求,具体还是看项目吧)

当然还有其他打包选项,各有利弊,具体看游戏实际情况需求。我这里只是对比出了告诉你打包选项会决定你的打出的资源包体大小和游戏中加载消耗内存。很重要。

具体打包选项BuildAssetBundleOptions参考:https://blog.csdn.net/AnYuanLzh/article/details/81485762

      补充:由上,我们知道打包时压缩方式会导致打出的包体和加载时的消耗都不同。加载时候的加载方式我们这边使用AssetBundle.CreateFromFile直接加载AssetBundle,Unity其实还提供了WWW加载AssetBundle的方式。但是这里不作详述了(讲不完...)。

五.总结    

      由上可知,文章虽说AB,Asset,GameObject三者联系,但是GameObject主要是由Asset实例化而来,GameObject是Asset的引用和复制的关系(主要引用),这个也可以说是Asset的一种。问题也就可以简化为AB和Asset之间的关系。

  

     由上图,再总结一下,打包方式不同,加载方式不同,造成的消耗不同。即,如果想优化游戏中的资源,需要注意打包AB的方式,以及加载AB的方式。当然,还要注意AB的卸载,和Asset的卸载。

六.参考    

    关于加载AssetBundle和加载Asset的区别,详情就不多说了,见UWA:https://blog.uwa4d.com/archives/ABTheory.html

    打包加密压缩算法区别参考:https://www.cnblogs.com/murongxiaopifu/p/5629415.html#autoid-3-3-0     

    附:测试Demo源码:链接:https://pan.baidu.com/s/1ZHPoQbuxgdUVh9PGbz6ArA   提取码:7lkv             

Unity AssetBundle,Asset,GameObject之间的联系的更多相关文章

  1. [Unity AssetBundle]Asset资源处理

    什么是AssetBundle 在很多类型游戏的制作过程中,开发者都会考虑一个非常重要的问题,即如何在游戏运行过程中对资源进行动态的下载和加载.因此,Unity引擎引入了AssetBundle这一技术来 ...

  2. 【Unity3D技巧】在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 (二) : 引入中间层NotificationCenter

    作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 一对多的观察者模式机制有什么缺点? 想要查看 ...

  3. Unity AssetBundle

    Unity AssetBundle爬坑手记 - 夜阑卧听风吹雨 时间 2014-09-15 16:55:00  博客园精华区原文  http://www.cnblogs.com/ybgame/p/39 ...

  4. Unity AssetBundle笔记

    1.入门: Resources:表示U3D自动将资源打成一个AssetBundle包,所有放在Resources下的文件夹都会打成一个AssetBundle包,资源非常大,Resources文件夹在真 ...

  5. Unity AssetBundle 踩坑记录

    Unity AssetBundle 踩坑记录 editor 下选择什么平台的 ab 加载 Material doesn't have a color property '_Color' UnityEd ...

  6. 【Unity3D技术文档翻译】第1.9篇 使用 Unity AssetBundle Browser tool (AssetBundle系列完结)

    上一章:[Unity3D技术文档翻译]第1.8篇 AssetBundles 问题及解决方法 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced D ...

  7. Unity AssetBundle爬坑手记

    这篇文章从AssetBundle的打包,使用,管理以及内存占用各个方面进行了比较全面的分析,对AssetBundle使用过程中的一些坑进行填补指引以及喷!   AssetBundle是Unity推荐的 ...

  8. (转)Unity AssetBundle爬坑手记

    转自:http://www.cnblogs.com/ybgame/p/3973177.html 这篇文章从AssetBundle的打包,使用,管理以及内存占用各个方面进行了比较全面的分析,对Asset ...

  9. Unity AssetBundle 游戏资源分类及关系

    --刚刚做完一个xlua的的热更项目,对AssetBundle资源分类总结一下.纯理论,闲谈知识,要是有建议,尽管提 ,不掺杂代码. --这里说说,AB是如何打包,如果下载,如何加载. 1.关键词理解 ...

随机推荐

  1. c语言学习笔记(3)——输入输出

    一.基本的输入和输出函数的用法 printf()  //屏幕输出 用法: (1)printf("字符串\n"); (2)printf("输出控制符", 输出参数 ...

  2. 新建py文件时取名千万要小心 不要和已有模块重名

    这是因为我新建了一个email.py的文件 后来我将文件名rename成了myemail.py没有看改名提示,结果导致所有的对email的import和调用全部改成了对myemail的import和调 ...

  3. win10下Linux子系统开启ssh服务

    原文:win10下Linux子系统开启ssh服务 为了便于交流共同学习,博主QQ群242629020(stm32-MCU认认真真交流群) 欢迎批评指导!!!电梯:https://jq.qq.com/? ...

  4. hdu3118Arbiter (使用二分图的定义,枚举每个状态)

    Arbiter Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Total Sub ...

  5. 狄利克雷过程(Dirichlet Process)

    0. 引入 现观察得到两个样本 θ1,θ2,来推测它们可能来自的分布: 假设来自于连续型概率密度函数, θ1,θ2∼H(θ) 则 θ1,θ2 相等的概率为 0,p(θ1=θ2)=0 概率为 0,不代表 ...

  6. WPF 路由事件 Event Routing

    原文:WPF 路由事件 Event Routing 1.路由事件介绍 之前介绍了WPF的新的依赖属性系统,本篇将介绍更高级的路由事件,替换了之前的.net普通事件.相比.net的事件,路由事件具有更强 ...

  7. WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮

    原文:WPF实用指南一:在WPF窗体的边框中添加搜索框和按钮 在边框中加入一些元素,在应用程序的界面设计中,已经开始流行起来.特别是在浏览器(Crome,IE,Firefox,Opera)中都有应用. ...

  8. LeapMotion Demo3

    原文:LeapMotion Demo3   从Github及其他论坛下载一些LeapMotion的例子,部分例子由于SDK的更新有一些小Bug, 已修复,感兴趣的可以下载:       http:// ...

  9. 用户控件(UserControl)

    简介 "用户控件"继承自UserControl,而UserControl继承自ContentControl,也就是内容控件UserControl和Window是一个层次上的,都有x ...

  10. DataGridView 鼠标双击获得行列索引

    如果是CellDoubleClick事件,可以在事件的参数e里获取列索引及行索引.也可以通过CurrentCell来获取当前选中的单元格的列索引及行索引.参考:private void dataGri ...