Unity载入和内存管理机制

Posted mfmdaoyou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity载入和内存管理机制相关的知识,希望对你有一定的参考价值。

Unity几种动态载入Prefab方式的差异:
事实上存在3种载入prefab的方式:

一是静态引用,建一个public的变量,在Inspector里把prefab拉上去,用的时候instantiate
二是Resource.Load,Load以后instantiate
三是AssetBundle.Load,Load以后instantiate
三种方式有细节差异。前两种方式,引用对象texture是在instantiate时载入,而assetBundle.Load会把perfab的所有assets都载入。instantiate时仅仅是生成Clone。所曾经两种方式,除非你提前载入相关引用对象。否则第一次instantiate时会包括载入引用类assets的操作,导致第一次载入的lag。官方论坛有人说Resources.Load和静态引用是会把所有资源都预先载入的。重复測试的结果,静态引用和Resources.Load也是OnDemand的。用到时才会载入。




几种AssetBundle创建方式的差异:
CreateFromFile:这样的方式不会把整个硬盘AssetBundle文件都载入到内存来,而是类似建立一个文件操作句柄和缓冲区,须要时才实时Load,所以这样的载入方式是最节省资源的。基本上AssetBundle本身不占什么内存。仅仅须要Asset对象的内存。可惜仅仅能在PC/Mac Standalone程序中使用。


CreateFromMemory和WWW.assetBundle:这两种方式AssetBundle文件会整个镜像于内存中。理论上文件多大就须要多大的内存。之后Load时还要占用额外内存去生成Asset对象。

什么时候才是UnusedAssets?


看一个样例:
Object obj = Resources.Load("MyPrefab");
GameObject instance = Instantiate(obj) as GameObject;
.........
Destroy(instance);
创建随后销毁了一个Prefab实例,这时候 MyPrefab已经没有被实际的物体引用了。但假设这时:
Resources.UnloadUnusedAssets();
内存并没有被释放,原因:MyPrefab还被这个变量obj所引用
这时候:
obj  = null;
Resources.UnloadUnusedAssets();
这样才干真正释放Assets对象
所以:UnusedAssets不但要没有被实际物体引用。也要没有被生命周期内的变量所引用。才干够理解为 Unused(引用计数为0)

所以所以:假设你用个全局变量保存你Load的Assets,又没有显式的设为null,那在这个变量失效前你不管怎样UnloadUnusedAssets也释放不了那些Assets的。假设你这些Assets又不是从磁盘载入的,那除了UnloadUnusedAssets或者载入新场景以外没有其它方式能够卸载之。


一个复杂的样例,代码非常丑陋实际也不可能这样做。仅仅是为了加深理解

IEnumerator OnClick()
{
    Resources.UnloadUnusedAssets();//清干净以免影响測试效果
    yield return new WaitForSeconds(3);
    float wait = 0.5f;
    //用www读取一个assetBundle,里面是一个Unity基本球体和带一张大贴图的材质。是一个Prefab
    WWW aa = new WWW(@"file://SpherePrefab.unity3d");
    yield return aa;
    AssetBundle asset = aa.assetBundle;
    yield return new WaitForSeconds(wait);//每步都等待0.5s以便于分析结果
    Texture tt = asset.Load("BallTexture") as  Texture;//载入贴图
    yield return new WaitForSeconds(wait);
    GameObject ba = asset.Load("SpherePrefab") as  GameObject;//载入Prefab
    yield return new WaitForSeconds(wait);
    GameObject obj1 = Instantiate(ba) as GameObject;//生成实例
    yield return new WaitForSeconds(wait);
    Destroy(obj1);//销毁实例
    yield return new WaitForSeconds(wait);
    asset.Unload(false);//卸载Assetbundle
    yield return new WaitForSeconds(wait);
    Resources.UnloadUnusedAssets();//卸载无用资源
    yield return new WaitForSeconds(wait);
    ba = null;//将prefab引用置为空以后卸无用载资源
   Resources.UnloadUnusedAssets();
   yield return new WaitForSeconds(wait);
   tt = null;//将texture引用置为空以后卸载无用资源
   Resources.UnloadUnusedAssets();
}

技术分享
技术分享
说明:
1        初始状态
2        加载AssetBundle文件后,内存多了文件镜像。用量上升,Total Object和Assets添加1(AssetBundle也是object)
3        加载Texture后。内存继续上升,由于多了Texture Asset,Total Objects和Assets添加1
4        载入Prefab后,内存无明显变化,由于最占内存的Texture已经载入,Materials上升是由于多了Prefab的材质,Total Objects和Assets添加6,由于 Perfab 包括非常多 Components
5        实例化Prefab以后,显存的Texture Memory、GameObjectTotal、Objects in Scene上升。都是由于实例化了一个可视的对象
6        销毁实例后,上一步的变化还原,非常好理解
7        卸载AssetBundle文件后,AssetBundle文件镜像占用的内存被释放。对应的Assets和Total Objects Count也减1
8        直接Resources.UnloadUnusedAssets,没有不论什么变化。由于全部Assets引用并没有清空
9        把Prefab引用变量设为null以后。整个Prefab除了Texture外都没有不论什么引用了。所以被UnloadUnusedAssets销毁,Assets和Total Objects Count减6
10        再把Texture的引用变量设为null,之后也被UnloadUnusedAssets销毁。内存被释放,assets和Total Objects Count减1。基本还原到初始状态

从中也能够看出:
Texture载入以后是到内存,显示的时候才进入显存的Texture Memory。
全部的东西基础都是Object
Load的是Asset,Instantiate的是GameObject和Object in Scene
Load的Asset要Unload,new的或者Instantiate的object能够Destroy

以上是关于Unity载入和内存管理机制的主要内容,如果未能解决你的问题,请参考以下文章

Unity5 怎样做资源管理和增量更新

Python 的内存管理机制

Unity ❉ 使用心得 ☀️| Unity中的 GC及优化 超级全面解析 ☆(ゝω・)v 建议收藏!

unity3d中怎么制作关卡载入进度条

跟我一起学Unity3D代码中分割图片而且载入帧序列动画

14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段