[Unity] Unity内存申请和释放

查看:1396 |回复:24 | 2015-10-12 20:01:28

您需要 登录 才可以下载或查看,没有账号?注册

x
本帖最后由 成林 于 2018-5-15 21:31 编辑

摘要: 加载资源的过程可以分为两个阶段,第一阶段是使用Resources.Load或者AssetBundle.Load加载各种资源,第二阶段是使用GameObject.Instantiate克隆出一个新的GameObject

59.jpg

1.资源类型

GameObject, Transform, Mesh, Texture, Material, Shader, noxss和各种其他Assets。

2.资源创建方式

  • 静态引用,在脚本中加一个public GameObject变量,在Inspector面板中拖一个prefab到该变量上,然后在需要引用的地方Instantiate;
  • Resource.Load,资源需要放在Assets/Resources目录下;
  • AssetBundle.Load, Load之后Instantiate。

3. 资源销毁方式


  • GameObject.Destroy(gameObject),销毁该物体;
  • AssetBundle.Unload(false),释放AssetBundle文件内存镜像,不销毁Load创建的Assets对象;
  • AssetBundle.Unload(true),释放AssetBundle文件内存镜像同时销毁所有已经Load的Assets内存镜像;
  • Resources.UnloadAsset(Object),释放已加载的Asset对象;
  • Resources.UnloadUnusedAssets,释放所有没有引用的Asset对象。

4. 生命周期
实验篇

实验中创建了一个简单场景,场景中创建了一个Empty GameObject,上面挂了一个脚本,在Awake函数中通过协程函数来创建资源,具体的Coroutine函数下面都有。
实验中创建的Prefab是一个坦克车,加入场景中场景内存增加3M左右,同时创建了一个AssetBundle资源供AssetBundle使用。

1. Resources.Load方式加载一个Prefab, 然后Instantiate GameObject
代码如下:




下面是统计结果:


从这里我们得出如下结论:

  • Resouces.Load一个Prefab相对于Instantiate一个资源来说是相对轻量的一个操作,上述过程中,Resources.Load加载一个Prefab几乎没有消耗内存,而Instantiate消耗了2.5M的资源空间。Resources.Load增加了Mesh和Total Object的数量,而Instantiate增加了GameObjects,Objects In Scene和Total Objects的数量;
  • Destroy一个GameObject之后,内存有所减少,但是比较少,本例中减少了0.6M;Instantiate和Destroy前后Material和Texture没有还原,用以后面继续进行Instantiate之用。

若没有调用Resources.UnloadUnusedAssets,则结果如下:


统计结果如下:


得出如下结论:
如果不手动执行Resources.UnloadUnusedAssets,则多余的Mesh,Material和Object不会主动释放。

2. 以AssetBundle.Load的方式加载一个Prefab,然后Instantiate一个GameObject
代码如下:




执行结果如下:


统计结果如下:


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

3. 通过静态绑定的方法来Instantiate一个资源
代码如下:




执行结果如下:


统计结果如下:


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

理论篇

  加载资源的过程可以分为两个阶段,第一阶段是使用Resources.Load或者AssetBundle.Load加载各种资源,第二阶段是使用GameObject.Instantiate克隆出一个新的GameObject。
  Load的资源类型包括GameObject, 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的GameObject使用的代码是一样的,而大家的数据有所区别,因此对数据段需要使用Clone的方式,而对代码段需要使用引用的方式来复制。
  因此Load操作其实Load一些数据源出来,用于创建新对象时被Clone或者被引用。
然后是销毁资源的过程。当Destory一个GameObject或者其他实例时,只是释放实例中那些Clone出来的Assets,而并不会释放那些引用的Assets,因为Destroy不知道是否有其他人在引用这些Assets。等到场景中没有任何物体引用到这些Assets之后,它们就会成为UnusedAssets,此时可以通过Resources.UnloadUnusedAssets来进行释放。AssetBundle.Unload(false)不行,因为它只会释放文件的内存镜像,不会释放资源;AssetBunde.Unload(true)也不行,因为它是暴力的释放,可能有其他对象在引用其中的Assets,暴力释放可能导致程序错误。
  另外需要注意,系统在加载新场景时,所有的内存对象都会被自动销毁,这包括了Resources.Load加载的Assets, 静态绑定的Assets,AssetBundle.Load加载的资源和Instantiate实例化的对象。但是AssetBundle.Load本身的文件内存镜像(用于创建各种Asset)不会被自动销毁,这个必须使用AssetBundle.Unload(false)来进行主动销毁。推荐的做法是在加载完资源后立马调用AssetBunble.Unload(false)销毁文件内存镜像。
  下图可以帮助理解内存中的Asset和GameObject的关系。



总结篇

  • 为了不出现首次Instantiate时卡顿的现象,推荐使用AssetBundle.Load的方式代替Resources.Load的方式来加载资源;
  • 加载完资源后立马调用AssetBunble.Unload(false)释放文件内存镜像;
  • Unity自身没有提供良好的内存申请和释放管理机制,Destroy一个GameObject会马上释放内存而不是进行内部的缓存,因此应用程序对频繁不用的对象如NPC,FX等进行对象池管理是必要的,减少内存申请次数;
  • 何时进行Resources.UnloadUnusedAssets是需要讨论的一个问题。

评分

参与人数 1元素币 +10 活跃度 +10 展开 理由
成林 + 10 + 10 --上面打错字了。。正文“不错啊。分享快乐”

查看全部评分

2015-10-12 20:01:28  
 赞 赞 1

使用道具 登录

24个回答,把该问题分享到群,邀请大神一起回答。
3#
资源甚好,发帖艰辛,且阅且珍惜!
回复 收起回复
2015-10-13 16:53:51   回复
 赞 赞 1

使用道具 登录

4#
资源发布哪家强?元素首发称大王!
回复 收起回复
2015-10-13 18:44:03   回复
 赞 赞 1

使用道具 登录

5#
元素那么大,我想来看看!
回复 收起回复
2015-10-13 19:33:44   回复
 赞 赞 1

使用道具 登录

6#
给力!元素有你更精彩
回复 收起回复
2015-10-13 20:26:36   回复
 赞 赞 1

使用道具 登录

7#
正能量帖子,顶一个
回复 收起回复
2015-10-13 21:41:34   回复
 赞 赞 1

使用道具 登录

8#
元素那么大,我想来看看!
回复 收起回复
2015-10-16 20:15:15   回复
 赞 赞 1

使用道具 登录

9#
不错
回复 收起回复
2015-10-18 21:21:04   回复
 赞 赞 1

使用道具 登录

10#
为了元素币,拼了!
回复 收起回复
2015-10-24 09:49:27   回复
 赞 赞 1

使用道具 登录

11#
正文“不错啊。分享快乐
回复 收起回复
2017-2-9 16:10:31   回复
 赞 赞 1

使用道具 登录

12#
666
回复 收起回复
2018-4-4 09:14:50   回复
 赞 赞 1

使用道具 登录

13#
回复 收起回复
2018-4-7 08:28:59   回复
 赞 赞 1

使用道具 登录

15#
学习了。
回复 收起回复
2018-6-30 13:41:14   回复
 赞 赞 1

使用道具 登录

16#
学习了。
回复 收起回复
2018-6-30 13:43:14   回复
 赞 赞 1

使用道具 登录

17#
学习了。
回复 收起回复
2018-6-30 13:45:55   回复
 赞 赞 1

使用道具 登录

18#
学习了。
回复 收起回复
2018-6-30 15:57:06   回复
 赞 赞 1

使用道具 登录

19#
从业不识微元素,做遍项目也枉然
回复 收起回复
2018-10-16 09:57:28   回复
 赞 赞 1

使用道具 登录

20#
666
回复 收起回复
2018-10-16 09:58:38   回复
 赞 赞 1

使用道具 登录

CG 游戏行业专业问题

Unity3D技术手机游戏引擎手游引擎
12下一页
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表