Go into the details unity resource loading and unloading

Reproduced, please indicate the source: http://www.cnblogs.com/zblade/

I. Summary

In the understanding of resource management unity, then go into the details about how Unity resources are loaded from disk into memory when running, and in turn how they are unloaded. This part is more complicated, more likely to write process.

Second, the script resource loading and unloading

In the unity of the script resource, can be divided into C ++ compiler engine dll file, c # compiled dll file, lua script file (lua-based method is more heat under).

Loading and unloading 2.1 dll file

In the Library / ScriptAssemblies project file folder, there will be a list of files dll non-engine related to the current project:

When the game starts, it will perform the operation Assembly.Load of these dll files are loaded into the process (editor classes relevant dll will not be loaded).

Can be loaded, naturally, can be unloaded at runtime, we now have a thermally update program ILRuntime dll file is to be loaded, hot update, unloading, loading such a way that the latest dll to operate. This thermal regeneration of mainly for Assembly-CSharp.dll / Assembly-CSharp- firstpass.dll operation.
If not, take the initiative to unload, then these are loaded dll file, in the course of the game, will not be uninstalled released only at the end of the game process, the system will be uninstalled out of memory.

Loading and unloading 2.2 lua files

Due to the nature lua script file that can be used as a text file type heat update, but before opening a Lua virtual machine when the game starts, before the implementation of related operations require Lua lua files in a virtual machine.
Load such documents, its essence is this part of the code is read into the global cache lua virtual machine, the so-called unloading, this part of the cache is set to nil, and loading and unloading the meaning of the above dll file has some difference.    

Third, non-scripting resources of loading and unloading

非脚本资源,才是整个游戏进程中需要处理的主要部分,会伴随整个游戏进程,直到游戏进程结束。
个人对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的使用和管理,属于新的分类内容,在后续再细谈。

Guess you like

Origin www.cnblogs.com/zblade/p/11095338.html
Recommended