zoukankan      html  css  js  c++  java
  • unity资源管理

    看100遍也记不住,画..




    整理下

    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());




    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;


    然后可以用

    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);
    }

    说下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 ();
    } 

    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时销毁或者放入空闲对象池进行重复利用,避免频繁创建销毁


  • 相关阅读:
    Redis持久化——AOF日志
    设计原则:接口隔离原则(ISP)
    设计原则:里式替换原则(LSP)
    新入职一家公司如何快速进入工作状态
    又是一年毕业季——如何入坑程序员
    设计原则:开闭原则(OCP)
    设计原则:单一职责(SRP)原则
    Redis持久化——内存快照(RDB)
    工作中应该如何管理自己的情绪?
    如何成为一个精力充沛的程序员——掌控
  • 原文地址:https://www.cnblogs.com/nafio/p/9137492.html
Copyright © 2011-2022 走看看