对象加载

作者: 归零者 分类: Unity3D优化 发布时间: 2018-09-01 09:59

以AssetBundle.Load的方式加载一个Prefab,然后Instantiate一个GameObject

结论:

通过WWW Load AssetBundle的方式加载一个资源时会自动加载相应的Mesh,Texture和Material,而通过Resources.Load方式进行加载只会加载Mesh信息。因此通过AssetBundle方式加载后Instantiate一个资源内存消耗较小,本例中AssetBundle.Load增加了2.5M的内存,而Instantiate增加了1.1M的内存。相比较Resources.Load后Instantiate的内存增量要小很多。

通过静态绑定的方法来Instantiate一个资源:

结论:

通过静态绑定的方法各种资源的加载顺序和Reources.Load的方式是一样的,一个GameObject创建时,其Component中静态绑定的Game Object只会增加Mesh信息,只有当该GameObject Instantiate出来之后才会加载Texture和Material信息。

 

 


加载资源的过程可以分为两个阶段,第一阶段是使用Resources.Load或者AssetBundle.Load加载各种资源,第二阶段是使用GameObject.Instantiate克隆出一个新的GameObject。Load的资源类型包括Game Object,Transform,Mesh,Texture,Material,Shader和noxss等各种资源,但是Resources.Load 和AssetBundle.Load是有区别的。

使用Resources.Load的时候在第一次Instantiate之前,相应的Asset对象还没有被创建,直到第一次Instantiate时才会真正去读取文件创建这些Assets,它的目的时实现一种OnDemand的使用方式,到该资源真正使用时才会去创建这些资源。

而使用AssetBundle.Load方法时,会直接将资源文件读取出来创建这些Assets,因此第一次Instantiate的代价会相对较小。

上述区别可以帮助我们解释为什么发射第一发子弹时候会有明显卡顿现象出现。

然后我们再来了解一下Instantiate的过程。Instantiate的过程是一个对Assets进行Clone(复制)和引用相结合的过程,Clone的过程需要申请内存存放自己的数据,而引用的过程只需要直接一个简单的指针指向一个已经Load的资源即可。例如Transform是通过Clone出来的,Texture和TerrainData是通过引用复制的,而Mesh,Material,PhysicalMaterial和noxss是Clone和引用同时存在的。以noxss为例,Script分为代码段和数据段,所有需要使用该Script分为代码段和数据段,所有需要使用该Script的GameObject使用的代码是一样的,而大家的数据有所区别,因此对数据段需要使用Clone的方式,而对代码段需要使用引用的方式来复制。

因此Load的操作其实Load一些数据源出来,用于创建新对象时被Clone或者被引用。然后是销毁资源的过程。当Destroy一个Game Object或者其它实例时,只是释放实例中那些Clone出来的Assets,而并不会释放那些引用的Assets,因为Destory不知道是否有其他人在引用这些Assets。等到场景中没有任何物体引用到这些Assets之后,它们就会成为UnusedAssets,此时可以通过Resources.UnloadUnusedAssets来进行释放。

AssetBundle.Unload(false)不行,因为它只会释放文件的内存镜像,不会释放资源;AssetBundle.Unload(true)也不行,因为它是暴力的释放,可能有其它对象在引用其中的Assets,暴力释放可能导致程序错误。

另外需要注意,系统在加载新场景时,所有的内存对象都会被自动销毁,这包含了Resources.Load加载的Assets,静态绑定的Assets,AssetBundle.Load 加载的资源和Instantiate实例化的对象。但是Asset Bundle.Load本身的文件内存镜像(用于创建各种Asset)不会被自动销毁,这个必须使用AssetBundle.Unload(false)l来进行主动销毁。推荐的做法就是在加载完资源后立马调用。

AssetBundle.Unload(false)销毁文件按内存镜像。

下图可以帮助我们理解内存中Asset和GameObject的关系:

 

1.为了不出现首次Instantiate时卡顿的现象,推荐使用AssetBundle.Load的方式代替Resources.Load的方式来加载资源;

2.加载完资源后立马调用AssetBunble.Unload(false)释放文件内存镜像;

3.Unity自身没有提供良好的内存申请和释放管理机制,Destroy一个GameObject会马上释放内存而不是进行内部的缓存,因此应用程序对频繁不用的对象如NPC,FX等进行对象池管理是必要的,减少内存申请次数;

4.何时进行Resources.UnloadUnusedAssets是需要讨论的一个问题。

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

说点什么

avatar
  Subscribe  
提醒
跳至工具栏