转载请标明出处:http://www.cnblogs.com/zblade/

一、概要

在了解unity的资源管理方式之后,接下来细谈一下Unity的资源是如何从磁盘中加载到运行时的内存中,以及又是如何被卸载的。这部分较为繁琐,可能会写较多的过程。

二、脚本资源的加载和卸载

在unity中的脚本资源,大体可以分为C++编译的引擎dll文件,c#编译的dll文件,lua脚本文件(基于lua热更的方式下)。

2.1 dll文件的加载和卸载

在工程的Library/ScriptAssemblies文件夹下,会有当前工程非引擎相关的dll文件列表:

在游戏启动的时候,会执行Assembly.Load的操作,将这些dll文件加载进进程中(editor类相关的dll不会被加载)。

能够加载,自然也能在运行时被卸载,所以目前一种热更新方案ILRuntime就是对dll文件进行加载,热更新,卸载,加载最新的dll这样的方式进行操作。这种热更新方式主要是针对Assembly-CSharp.dll/Assembly-CSharp-firstpass.dll进行操作。
如果不是主动进行卸载,那么这些被加载的dll文件,在游戏进程中,是不会被卸载释放的,只有在游戏进程结束的时候,才会被系统从内存中卸载出去。

2.2 lua文件的加载和卸载

lua由于脚本文件的属性,可以被当做类文本文件进行热更新,同时在游戏启动的时候才开启一个Lua虚拟机,在Lua虚拟机中才执行lua文件的require相关操作。
这类文件的加载,其实质就是将这部分代码读入到lua虚拟机的全局缓存中,而所谓的卸载,就是将这部分缓存置为nil,和上面的dll文件的加载和卸载含义有一些差异。

三、非脚本资源的加载和卸载

非脚本资源,才是整个游戏进程中需要处理的主要部分,会伴随整个游戏进程,直到游戏进程结束。
个人对unity对资源的加载过程的理解,其本质就是一个反序列化的过程。

3.1 Serialization and Instance

unity在序列化的时候,对于每个组件,也是单独逐个的执行序列化的操作的,其序列化信息的关键信息是文件本身的fileID, 以及依赖文件的fileID 和guid.
对应的,在unity的Instance操作中,unity会为该GameObject创建一个唯一的InstanceID, 在进程内部会缓存这样一个InstanceID <-> gameobject的映射关系表,同时 fileID/GUID/LocalID 会对应的映射到该文件的源文件存储位置。这个InstanceID具有唯一性,当InstanceID创建完成后,如果object没有被load,则会触发unity执行一次资源的load,基于fileID/Guid/local id来执行object的加载。
实际的游戏运行中,并不会直接依赖fileID/GUID来执行文件的映射,而是会将这两个ID转换成一个新的ID,所以在实际运行的游戏中是看不到fileID/GUID相关文件的。

3.2 InstanceID的创建和失效

在游戏启动的时候,会将启动场景以及Resources目录下的资源逐个创建对应的InstanceID, 放入到缓存中,这部分InstanceID的创建耗时会随着Resources目录包含资源的增多而增大,所以尽量减小这部分资源的数目。
在游戏启动完成后,后续按需加载的Object,都会对应的创建InstanceID, 在卸载该资源的时候,会对应使这个映射关系失效,后续重新加载该object的时候,是会被重新创建对应的InstanceID, 先前创建的InstanceID是不会被重新定位到新加载的Object的。

3.3 AssetBundle中文件的加载

现在在Unity中主要的资源管理是基于AssetBundle的管理,那么运行时,是如何从bundle中加载出想要的Object的?

3.3.1 Bundle文件的组成

在Unity中,bundle会被分为两种大类,场景Bundle和非场景Bundle,利用unity自带的WebExtract 和 Binary2Text两个工具,是可以解压bundle为文本文件的。
场景Bundle在使用WebExtract解压后,会得到两类文件:

  • BuildPlayer-sceneName: 场景序列化文件,也就是hierarchy序列化的结果
  • BuildPlayer-sceneName.sharedasset: 场景依赖的文件

普通bundle在使用WebExtract解压后,会得到两类文件:

  • CAB-GuidString: 该二进制文件为该bundle的序列化文件,以及可能包含的具体Object文件
  • CAB-GuidString.resS:如果包含这个文件,则上面的文件目前是不能转换成txt文件的

以转换成功的bundle的序列化文件为参照,可以分析主要包含以下几个部分:

1) External References:

可以理解为依赖的外部assetbundle,这儿并不是依赖的bundle的名字,而是类似的cab-guidstring的形式,可见unity内部对于bundle的相互依赖处理,是基于这样一套的命名来进行管理的。

2) object map:

当前bundle包含的object的信息map:

3) bundle头文件: AssetBundle

4) bundle包含的object的详细序列化信息

3.3.2 Bundle文件的加载过程

分析完bundle的组成后,接下来分析从bundle中加载Object的过程,这儿以LZ4的压缩为标准,基于AssetBundle.LoadFromFile(Async)做为接口。 在加载Object的时候,会首先触发加载该object所在的bundle,如果该bundle有依赖bundle,那么需要先加载该bundle的依赖bundle,Unity并不会自动加载依赖bundle.

unity在加载bundle的时候,会先加载该bundle的序列化文件,也就是前面说到的External References/Object map/bundle头文件,然后基于得到序列化信息,进一步从bundle的object序列化信息中加载对应的object。

如果该object有多个依赖的资源,unity会在内部自动从该bundle或者依赖bundle中将依赖资源加载出来,然后执行资源的装载,最终返回一份实例到内存中,完成InstanceID 和 gameobject的映射。

3.3.3 Bundle文件中对script的加载

如果bundle中的object上有对应的script,那么在构建Bundle的时候,会为这个script构建一份特殊的资源:MonoScript,对应的存入到bundle中,monoscript这种资源,并没有包含实际的运行时的代码,而是存储这个脚本的assembly name, namespace name and class name,在装配该Object的时候,由于dll已经提前装载,所以会自动的索引到装载的assembly/namespace/class name脚本,然后装配到该object上。

3.4 资源的卸载

在不考虑资源计数管理的情况下,当资源的引用为空的时候,是可以执行资源的卸载的。对于资源的卸载,分为Resources资源和bundle资源:

3.4.1 Resources资源

1)可以调用Resources.UnloadAsset接口来卸载资源,使用该接口后,下次再加载该Object,会重新建立旧InstanceID和该Object的映射关系

2) 在执行场景切换的时候,如果选择 non-additively mode,这时候会自动的触发Resources.UnloadUnusedAsset

3.4.2 Bundle资源

bundle的卸载,有AssetBundle.Unload(true)/Unload(false)两种:

1)Unload(true): 将bundle从内存中卸载,同时将从bundle中加载的所有资源都卸载掉

2) Unload(false): 将bundle从内存中卸载,从bundle中已经加载的资源会被保留,如果再重新加载该bundle,对应的不会重新构建bundle和资源的映射关系,以前加载的资源就容易造成内存泄露。

目前推荐自己计数管理,只调用Unload(true)

四、Resources的使用

Unity的官方文档:

4.1. Best Practices for the Resources System

Don't use it. several reasons:

1) 使用resources使得精细化细粒度的内存管理更困难

2) 不恰当的使用Resources目录会增大游戏的启动时间以及build时间
而且随着Resources目录中文件的增加,对其中资源的管理会越来越困难

3) Resources目录无法根据平台定制资源内容(除非在build的时候重新拷贝指定的资源到Resource目录)

4) Resources目录无法提供热更新

4.2. Proper uses of the Resources system

在某些情况下,Resources目录还是可以使用:

1) rapidly prototype开发阶段

2) generally required throughout a project's lifetime

3) Not memory-intensive

4) Not prone to patching, or does not vary across platforms or devices

5) Used for minimal bootstrapping 某些和平台无关的配置文件,不占用较大内存,可以放入到Resources目录中

4.3. Serialization of Resources

在build的时候,Resources目录下的Assets/Objects会被序列化到一个序列化文件中。在这个文件中,包含了元数据以及索引信息,类似于AssetBundle。

索引信息其实就是一个序列化的查找树,用来定位资源名字到资源的file guid和local ID, 同时用于查找这个资源本身。

在大部分的平台上,查找树是BST, 其构建的时间复杂度为O(nlog(n)), 构建的时间会随着n的增大而增大(资源数越多构建时间越久)

在游戏启动的时候,这个BST树构建的过程是无法跳过的,如果Resources下的资源数目超过10,000,在低端手机上其占用的启动时间会达到几秒。而事实上这些资源索引并不是全部需要预先加载的,这会降低游戏的性能。

五、总结

简要的阐述了整个资源加载和卸载的流程,对于AssetBundle的使用和管理,属于新的分类内容,在后续再细谈。

细谈unity资源加载和卸载的更多相关文章

  1. Unity资源 ----加载最好需要做哪些事

    先上图解 一.基本关键词 1)AssetBundle:一种保存“一个或多个资源的转变为某种利于传输等的特殊格式(二进制之类)”的文件.(我这边是使用Unity制作手游的角度来说明) 简称AB. 2)对 ...

  2. Unity资源加载路径及加载方式小结

    Unity3D中的资源路径路径属性 路径说明Application.dataPath 此属性用于返回程序的数据文件所在文件夹的路径.例如在Editor中就是Assets了.Application.st ...

  3. 再谈DOMContentLoaded与渲染阻塞—分析html页面事件与资源加载

    浏览器的多线程中,有的线程负责加载资源,有的线程负责执行脚本,有的线程负责渲染界面,有的线程负责轮询.监听用户事件. 这些线程,根据浏览器自身特点以及web标准等等,有的会被浏览器特意的阻塞.两个很明 ...

  4. 【原】从一个bug浅谈YUI3组件的资源加载

    篇前声明:为了不涉及业务细节,篇内信息统一以某游戏,某功能代替 前不久,某游戏准备内测客户端,开发人员测试过程中发现某功能突然不灵了,之前的测试一切ok,没有发现任何异常,第一反应是,游戏内浏览器都是 ...

  5. Unity -- AssetBundle(本地资源加载和加载依赖关系)

    1.本地资源加载 1).建立Editor文件夹 2).建立StreamingAssets文件夹和其Windows的子文件夹 将下方第一个脚本放入Editor 里面 脚本一  资源打包AssetBund ...

  6. Unity动态加载和内存管理(三合一)

    原址:http://game.ceeger.com/forum/read.php?tid=4394#info 最近一直在和这些内容纠缠,把心得和大家共享一下: Unity里有两种动态加载机制:一是Re ...

  7. 详谈 Unity3D AssetBundle 资源加载,结合实际项目开发实例

    第一次搞资源更新方面,这里只说更新,加载,AssetBundle资源加载,谈谈自己的理解,以及自己在项目中遇到的那些神坑,现在回想一下,真的是自己跪着过来的,说多了,都是泪. 我这边是安卓AssetB ...

  8. AssetBundle使用心得【资源加载】

    0.资源加载方式 静态资源 Asset下所有资源称为静态资源 Resources资源 Resources目录下,通过实例化得到的资源 AssetBundle资源 又称为增量更新资源 1.什么是Asse ...

  9. unity动态加载(翻译) .

    AssetBundles are files which you can export from Unity to contain assets of your choice. These files ...

随机推荐

  1. In partitioned databases, trading some consistency for availability can lead to dramatic improvements in scalability.

    In partitioned databases, trading some consistency for availability can lead to dramatic improvement ...

  2. svg查看预览 , 鼠标控制放大缩小 , 托拉拽等

    自己写是不可能了 , 所以要借用插件 svg-panzoom.js 地址 : https://github.com/ariutta/svg-pan-zoom#demos 及常见问题https://ww ...

  3. UVa 12657 Boxes in a Line(应用双链表)

    Boxes in a Line You have n boxes in a line on the table numbered 1 . . . n from left to right. Your ...

  4. 实现网站https

    双击上面的服务器证书 如下图:

  5. 罚函数(penalty function)的设计

    1. encourage sparsity ℓ0 范数: non-differentiable and difficult to optimize in general ℓ1 范数: 对数约束,log ...

  6. leetcode先刷_Pascal&#39;s Triangle II

    三角相对简答题.第一个问题是太简单.我不沾了,我一定会写.其实没什么的第二个问题,与这个问题计算路径有点像一个三角形,假定输入是n,然后从第一行计数到第一n行,保存在数据线上的时间到,由于只有相关的事 ...

  7. 好用的Markdown 编辑器及工具

    Markdown 是 2004 年由 John Gruberis 设计和开发的纯文本格式的语法,所以通过同一个名字它可以使用工具来转换成 HTML.readme 文件,在线论坛编写消息和快速创建富文本 ...

  8. x:Static , StaticResource 和DynamicResource等XAML 扩展用法

    原文:x:Static , StaticResource 和DynamicResource等XAML 扩展用法 前提: <system:String x:Key="{Component ...

  9. 【开源】jquery省市区插件

    先来张效果图,演示地址:http://long-woo.github.io/jquery-city/ 1.动画效果使用的是animate.css 2.支持选择和键盘输入(中英文输入) 3.服务端返回的 ...

  10. 【shell】gerrit同步备份脚本的实现

    本期分享下gerrit如何实现备份,由于之前的一台代码服务器直接down掉,所以为了以防万一,开始备份gerrit数据,有人说,gerrit不过是个审查代码的工具,备份这个做什么,git是分布式代码管 ...