Unity资源管理策略

看100遍也记不住,画..

unity资源管理_sed



整理下Assetbundle

首先说下Assetbundle,感觉这一个词有2个意思


1 通过BuildAssetBundle打出的.unity3d文件是就是Assetbundle文件,姑且叫资源Assetbundle文件吧

2 然后从打包AssetBundle文件中读取出来一些二进制,需要有一个中间结构管理这个二进制流,这个用来管理的也叫AssetBundle(通过www.assetbundle或Assetbundle.CreateFromMemory从二进制流中获取),姑且叫引用AssetBundle(这个结构是个struct,只是一个引用,占用较少内存)

web stream(二进制)分为3部分  

1压缩assetbundle

这部分的释放分2种

如果是从www加载的,www=null或www.dispose时会被释放。

如果是从打包Assetbundle中导入的二进制bytes[]载入的,当找到引用Assetbundle后这个原始压缩二进制就没用了,立刻释放bytes[]=null就可以了,释放掉的是压缩assetbudle的二进制资源,解压后的资源一定还在内存中。


2解压后assetbundle  

这里是Texture,mesh等资源的二进制原始形式。

这部分当引用计数为0时自动释放,而对其引用的正是引用Assetbundle,引用Assetbundle被卸载引用就减1


3 引用assetbundle(一个映射结构,占用较少内存)




创建



1 www方式

www.assetbundle

具体方法,注意用www加载加载的是压缩的资源Assetbundle,并且路径要加file://(相对于CreateFromFile的path而言 ,并且是在PC上,其他平台没试)

登录后复制

IEnumerator tw(){    WWW w = new WWW("file://"+path);    yield return w;    ab = w.assetBundle;    if(ab==null)Debug.Log("ab shit!");    else Debug.Log("ab ok!");  }  StartCoroutine(tw());1.2.3.4.5.6.7.8.9.





2 CreateFromFile:

这种方式不会把整个硬盘AssetBundle文件都加载到内存来(得到引用assetbundle时内存基本不会增加),而是类似建立一个文件操作句柄和缓冲区,需要时才实时Load,所以这种加载方式是最节省资源的,基本上AssetBundle本身不占什么内存,但要特别注意,这个方法需要使用未压缩的资源Assetbundle包

就是说打包时用

BuildPipeline.BuildAssetBundle(obj,null, savePath,BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.UncompressedAssetBundle,BuildTarget.StandaloneWindows);

替换

BuildPipeline.BuildAssetBundle(obj,null, savePath,BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets,BuildTarget.StandaloneWindows);


3 Assetbundle.CreateFromMemory(读取二进制)

等方式获取引用Assetbundle,这个方法优点是方便对二进制做加密

这里有点小坑,这种获取方法具体方式为

登录后复制

AssetBundleCreateRequest abcr = AssetBundle.CreateFromMemory(ba);AssetBundle assetBundle = abcr.assetBundle;1.2.



然后可以用

UnityEngine.Object obj = assetBundle.mainAsset

单独打包(每个资源打成单独的资源Assetbundle文件)时一般可以用这个方法,打包代码为

登录后复制

UnityEngine.Object[] selection = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);foreach (UnityEngine.Object obj in selection){  bool ret=  BuildPipeline.BuildAssetBundle(obj,null, savePath,BuildAssetBundleOptions.CollectDependencies|BuildAssetBundleOptions.CompleteAssets,BuildTarget.StandaloneWindows);}1.2.3.4.


说下BuildPipeline.BuildAssetBundle()的参数

这里第一个参数obj(UnityEngin.Object类型)是主要资源,方便通过引用Assetbundle.mainAsset获取的资源

第二个参数是打包时的全部资源,是UnityEngin.Object[]类型,上面这个参数写的null因为是单独打包,也可以按下面写,把所有资源打到一个资源AssetBundle包中

登录后复制

Object[] SelectedAsset = Selection.GetFiltered (typeof(Object), SelectionMode.DeepAssets);if (BuildPipeline.BuildAssetBundle (null, SelectedAsset, Path, BuildAssetBundleOptions.CollectDependencies)) {  AssetDatabase.Refresh ();} 1.2.3.4.


assetBundle.load(),assetBundle.loadAsync()通过资源名来载入具体的asset(资源)






卸载




调用assetbundle.unload(false)其实就是把这个assetbundle的引用减1(并且仅仅是引用减1,所以说其实assetbundle.unload(false)这个调用只释放了引用assetbundle这个struct,并没有直接释放其他任何资源)

assetbundle.unload(true)除了unload(false)的功能,还卸载了从引用assetbundle中创建出的aseet,个人感觉assetbundle.unload(true)完全可以被Resource.UnloadAsset(obj)加assetbundle.unload(false)替换掉,没必要用


从引用Assetbundle中获取的Asset(资源)

UnityEngine.Object类型

单独打包用UnityEngine.Object obj = assetBundle.mainAsset获取Asset资源

多资源打包用assetBundle.load获取Asset资源

这里的asset资源就是Texture,mesh,Audio等真正游戏中用到的资源

这些资源实际是资源assetbundle文件解压后二进制文件的引用(一张图Texture,在非依赖打包的情况下,被同时打进多个资源Assetbundle中,那么这些Assetbundle被加载后Texture实际在内存中有多个副本,所以需要依赖打包来解决同一资源多个副本的问题)


使用Resource.UnloadAsset(obj) Resource.UnloadAllUnusedAssets()来卸载

assetbundle.unload(true)也可以卸载Asset

通过Instantiate实例化出的GameObject


通过GameObject.Destroy()来释放





Prefab


prefab的原理与assetbundle类似






加载方式


Resource.Load();这个过程其实就是从一个缺省打进程序包里的AssetBundle里加载资源




实例化




Instaniate一个Prefab,是一个对Assets进行Clone(复制)+引用结合的过程


Gameobject是新Clone出来的,其他资源mesh ,texture,audio等是引用


对一个Prefab重复instaniate时,GameObject每次都Clone出新的,而其他asset资源都是对Resource.Load创建出的缺省AssetBundle中asset的引用






存在3种加载prefab的方式:


1是静态引用,建一个public的变量,在Inspector里把prefab拉上去,用的时候instantiate


2是Resource.Load,Load以后instantiate


3是AssetBundle.Load,Load以后instantiate


三种方式有细节差异,前两种方式,引用对象texture是在instantiate时加载,而assetBundle.Load会把perfab的全部 assets都加载,instantiate时只是生成Clone。所以前两种方式,除非你提前加载相关引用对象,否则第一次instantiate时会 包含加载引用类assets的操作,导致第一次加载的lag。



卸载



总结

assetbundle中内存的占用情况


1 压缩的资源assetbundle占用(内存占用量高),在获取到引用assetbundle后立刻手动释放


2 解压资源assetbundle 的解压buffer占用,unity负责自动释放


3 解压后的资源assetbundle(asset资源的原始二进制)占用(内存占用量高),这个只有引用为0时unity负责自动释放,减少引用就是unload 引用assetbundle


4 引用assetbundle(一个struct,用来引用解压后的资源assetbundle二进制)(内存占用少),一旦从这个引用assetbundle获取到asset文件,就可以手动清理掉,减少引用计数,而一旦引用数为0,解压后的资源assetbundle就被释放了,所以释放这个引用assetbundle很重要


5 UnityEngine.Object类型(具体类型为Texture,mesh,audio等)的asset(资源)对象 内存占用量高):

如果asset来源是本地,使用Resource.Load加载

asset是非prefab,Resource.Load后,会分配Asset内存

asset是prefab,Resource.Load后,不会分配Asset内存,Instaniate后才分配,卸载时先GameObject.Destroy(),prefab=null,然后调用Resource.UnloadAllUnusedAssets()


如果asset来源是本地或网络的资源Assetbundle文件

asset是非prefab,assetBundle.LoadAsset()后,会分配Asset内存

asset是prefab,assetBundle.LoadAsset()后,会分配prefab相关的所有asset内存,而instaniate时只新创建Go,卸载时先GameObject.Destroy(),prefab=null,然后调用Resource.UnloadAllUnusedAssets()


Resource.UnloadAllUnusedAssets()最好配合GC.Collect();使用


如果同一个asset被打入两个不同的assetbundle包,那么从这两个包中载出的asset不是用一个引用,所以打包要用依赖包,把共享资源放在一起,给其他资源依赖,减少统一资源占用多份内存


6 实例化出的GameObject对象(内存占用少),不需要GameObj时销毁或者放入空闲对象池进行重复利用,避免频繁创建销毁


         

免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空