看100遍也记不住,画..
整理下Assetbundle
首先说下Assetbundle,感觉这一个词有2个意思
1 通过BuildAssetBundle打出的.unity3d文件是就是Assetbundle文件,姑且叫资源Assetbundle文件吧
2 然后从打包AssetBundle文件中读取出来一些二进制,需要有一个中间结构管理这个二进制流,这个用来管理的也叫AssetBundle(通过www.assetbundle或Assetbundle.CreateFromMemory从二进制流中获取),姑且叫引用AssetBundle(这个结构是个struct,只是一个引用,占用较少内存)
web stream(二进制)分为3部分
这部分的释放分2种
如果是从www加载的,www=null或www.dispose时会被释放。
如果是从打包Assetbundle中导入的二进制bytes[]载入的,当找到引用Assetbundle后这个原始压缩二进制就没用了,立刻释放bytes[]=null就可以了,释放掉的是压缩assetbudle的二进制资源,解压后的资源一定还在内存中。
这里是Texture,mesh等资源的二进制原始形式。
这部分当引用计数为0时自动释放,而对其引用的正是引用Assetbundle,引用Assetbundle被卸载引用就减1
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时销毁或者放入空闲对象池进行重复利用,避免频繁创建销毁
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删