AssetBundle打包

AssetBundle技术的概念

  Unity的AssetBundle是一个资源压缩包,包含模型、贴图、预制体、声音甚至整个场景,可以在游戏运行时被加载。
  AssetBundle自身保存着相互的依赖关系,压缩包可以使用LZMALZ4压缩算法,减少包大小,更快的进行网络传输,把一些可以下载的内容放在AssetBundle里面,可以减少安装包的大小。

AssetBundle的本质

  AssetBundle是一个存于硬盘上的文件,压缩包中包含了多个文件,如各种图片、声音等等,方便快速加载,可以在Editor上读取,方便查看,可以通过代码从一个特定的压缩包中加载出来对象,这个对象包含了所有添加到这个压缩包里面的内容,可以通过这个对象加载出来

AssetBundle的作用

  AssetBundle的主要作用为优化安装包的大小,如比较耗费资源的模型、场景、预制体等资源都可以放到AssetBundle包中,在运行时动态下载后加载,安装包就不会那么大。

打包(资源分包)的策略

  生成AssetBundle包是不能将所有的资源都生成到一个包中,因为这样会导致AssetBundle包的体积过大,造成下载 加载过慢 会影响用户体验 ,也不能为每个资源生成一个包,这样会耗费大量的加载时间,也会影响用户体验。

常用的打包分组策略
  1. 安装逻辑实体分组
    一个UI界面或者所有UI界面为一个包
    一个角色或者所有角色为一个包
    所有场景共享的部分为一个包
  2. 按照类型分组
    所有声音资源为一个包
    所有Shader为一个包
    所有模型为一个包
    所有材质为一个包
  3. 按照使用分组
    把在某个时间内使用的所有资源打包成一个包
    按照关卡分 一个关卡需要的所有资源 包含角色 贴图 声音等为一个包
    按照场景分 一个场景需要的资源为一个包

打包注意事项
把经常更新的资源放在一个单独包内 与不经常更新的包分离
把需要同时加载的资源放在一个包内
可以把其他包共享的资源放在一个单独的包中
把一些需要同时加载的小资源打包成一个包

  Unity中AssetBundle的打包和分包策略主要针对资源的整理和分组,以方便管理,又能有效优化资源的加载和内存使用。

资源管理的途径

  1. 打包资源的预处理:为了减少AssetBundle的大小和数量,可以先对资源进行预处理,如压缩纹理、优化模型、剪辑音频等
  2. 资源的分组打包
  3. 公共资源的处理
  4. 加载依赖的管理
  5. 版本管理

热更新的步骤

  1. 总体步骤:
    资源打包(开发者)
    上传服务器(开发者)
    从服务器下载(客户端)
    资源包解包并加载数据到程序中(客户端)

资源打包成AssetBundle:
对场景的资源做一个标记,该标记用于确定哪些资源需要打包,已经打包时的分类
在这里插入图片描述

[MenuItem("AssetBundle/Build")]
public void Build()
{BuildPipeline.BuildAssetBundles(Application.dataPath+"/AssetBundles");
}

注意点:

要打包的资源的Asset Label必须全部小写(大写会被自动转换为小写),可以带扩展名、版本名

形如“xxx/yyy”的Asset Label 会转化为xxx文件夹下的yyy资源包

面试场景:如何按照路径去打包资源

答:给每一个资源添加一个路径(Asset Label) + / 资源包的名称

Unity会自动处理依赖关系:
比如一个模型依赖于一个材质,如果模型和材质分属不同AssetBundle,则材质中的贴图文件变化时,只需要更新材质的AssetBundle即可,从而减少资源打包的时间和数量。

Unity能够支持任意一种该引擎能够识别的资源类型的打包:
除了脚本资源,移动平台不支持网络下载脚本并执行,因为可能会存在安全隐患,从而导致游戏上架审核失败。

脚本资源的热更新需要额外处理:方法就是利用C#反射机制绑定UnityAPI,在上层进行调用(此外,你无法调用你通过审核以外的API功能)

Unity支持txt、xml、json格式的文件打包,预制体、模型、音频、贴图等都可以打包,但无法打包脚本。

关于二进制资源的打包:

  • Unity支持二进制资源的打包
    • 扩展名以.bytes结尾。
    • Unity会将其识别为TextAsset类型。
    • 在将二进制文件下载到本地后,程序员按TextAsset类型对其进行解包。
    • 也可以将其他Unity不能识别的格式的资源改名为.bytes进行打包。

手机上需要发布到Application.streamingAssetsPath下,因为只有该目录下的内容会被发布到真机上(首先需要新建一个Assets/Streaming Assets文件夹)

打包场景需要调用BuildPipeline.BuildPlayer();方法

热更新时序图
在这里插入图片描述动态加载的好处:
如果游戏场景资源比较多,按需加载可以降低消耗
比如大地图的MMORPG这样的类型的游戏,更是要降低消耗,按需加载

3、资源包上传到服务器

4、从服务器下载资源到本地
非缓存方式:

string url="file:///"+Application.dataPath+"/AssetBundles/XXX";
WWW www=new WWW(url);
yield return www;file///:这是表示紧跟其后的路径指向本地文件系统的协议前缀。在file:后面的三斜杠是标准用法,用于表示一个不含主机消息(因为我们处理的事本地文件)的绝对文件路径。

缓存方式:

WWW www=WWW.LoadFromCacheOrDownload(url,version);//这里的版本可以从服务器的version.cfg文件下载。
yield return wwww;
	WWW www;public Text text;void Start(){//完善的热更新解决方案需要以下步骤//启动程序时,将StreamingAsset中的资源包移动到PersistantDataPath//检查服务器上资源有没有发生更新,有的话下载更新//简单学习,只要从服务器下载资源并载入数据即可StartCoroutine(DownLoadAB());//启动携程}public IEnumerator DownLoadAB(){//print("DownLoadAB");//yield return null;//yield break;//中断协程www = new WWW("http://localhost:6688/AssetBundles/my");yield return www;//等待下载结束print("Download complete");GameObject cubePrefab= www.assetBundle.LoadAsset<GameObject>("MyCube.prefab");Instantiate(cubePrefab);}private void Update(){text.text = string.Format("{0}%", www.progress * 100);}

总资源加载

一般不能直接在Update中下载资源,而是由主线程显示下载的进度,开启携程下载数据
当不清楚资源的依赖关系时,可以先将其总资源包加载,取得相关的依赖项进行加载

 //下载总资源包www = new WWW("http://localhost:6688/AssetBundles/AssetBundles");yield return www;AssetBundleManifest mainfest = www.assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//取得相关的依赖项string[] dep = mainfest.GetAllDependencies("我的预制体");//将相关的依赖项全部加载foreach (string s in dep){//print(s);www=new WWW("http://localhost:6688/AssetBundles/"+s);yield return www;www.assetBundle.LoadAllAssets();}

注意
1、www的资源是直接加载到内存中的,所以用完就要即时释放

//未用资源的加载
www.assetBundle.Unload(false);

2、www的资源不能缓存,需要我们手动实现数据缓存已经和服务器版本比较功能。

卸载AssetBundle:
Asset加载进来后就可以释放AssetBundle了,调用AssetBundle.Unload(unloadAllLoadedObjects)即可。

  • 传入true:卸载该bundle中所有的Asset
  • 传入false:卸载当前未被使用的所有的Asset

5、解包AssetBundle


AssetBundle的使用

AssetBundle工作流程

主要作用:在游戏运行过程中对资源进行动态的下载和加载。
通过AssetBundle将游戏中所需的各种资源打包压缩并上传到网络服务器上
在运行时游戏可以从服务器上下载该资源,从而实现资源的动态加载。

AssetBundle的工作流程

1、开发过程中,开发者创建AssetBundle文件并上传到服务器上。
  创建AssetBundle:开发者可以在Unity编辑器中通过脚本来创建满足要求的AssetBundle文件夹。

  上传至服务器:开发者创建好AssetBundle文件后,即可通过上传工具(比如FTP等)将其上传至服务器中,从而使游戏通过访问服务器来获取所需的资源。

  游戏运行时,客户端会根据实际需求从服务器上将适当的AssetBundle下载到本地机器,再通过加载模块将其资源加载到游戏当中。

  下载AssetBundle:Unity提供了一套完整的API 供开发者使用,从而完成从服务端下载AssetBundle文件。

   www = new WWW("http://localhost:6688/AssetBundles/my");yield return www;//等待下载结束GameObject cubePrefab= www.assetBundle.LoadAsset<GameObject>("MyCube.prefab");

  加载AssetBundle中的Asset:AssetBundle文件一旦下载完成,开发者即可通过特定的API来加载其所包含的Assets,包括模型、纹理、动画片段等。

  Unity5对Unity4的AssetBundle系统进一步简化,提供了更简单的UI和更简单的脚本,Unity在Build时会自动处理依赖关系,并生成一个.manifest文件,以及AssetBundle的增量式发布。

AssetBundle在Unity中的使用

  AssetBundle是Unity引擎提供的一种用于存储资源的文件格式,它可以存储任意一种Unity引擎能够识别的资源,例如模型、纹理、音频、动画片段甚至整个场景。

  同时,AssetBundle也可以包含开发者自定义的二进制文件,只需将二进制文件的后缀名改为".bytes",Unity引擎即可将其识别为TextAsset,进而可以被打包到AssetBundle文件中

  用户可以通过AssetBundle的UI和简单的脚本在Unity中创建AssetBundle文件,Unity引擎提供了二中创建AssetBundle的API

BuildPipeline.BuildAssetBundles()
通过该接口,开发者可以将编辑器中指定的Asset打包
BuildPipeline.BuildPlayer()
通过该接口,开发者可以讲场景编译成播放器

AssetBundle的UI

  Unity5提供了一个简单AssetBundle的UI,可以让用户简单快速的将Asset标记到AssetBundle

  在资源的Inspector视图中的下方会出现一个AssetBundle的UI,其中第一个选项表示该资源所标记的AssetBundle名称(即该资源会打包到这个名称的AssetBundle中),第二个参数用于设置AssetBundle Variant,主要应用在不同分辨率资源的使用和动态替换AssetBundle。

  当AssetBundle标记的对象很多时,想要看到某个AssetBundle中的资源时,可以单击AssetBundle的名称选项,在弹出的菜单中选择”Filter Selected Name”项,或者在Project视图中搜索”b:AssetBundle名称”,即可查找该AssetBundle里包含的所有资源

  AssetBundle的标记名称要小写,可以有后缀(如:a.assetbundle/a.unity3d),Script(脚本)不能标记AssetBundle。

BuildPineline.BuildAssetBundles

public static AssetBundleMainfest BuildAssetBundles(string outputPath ,BuildAssetBundleOPtions assetBundleOptions=BuildAssetBundleOptions.None ,BuildTarget targetPlatform=BuildTarget.WebPlayer)

如果要将多个资源一起打包,只要将它们的AssetBundle名称设置成一样就可以了

AssetBundle的增量式打包仅重新打包发生变化的AssetBundle,当Asset文件发生变化或者TypeTree发生变化时才会重新打包。

BuildPileline.BuildPlayer()

BuildPlaye()

public static string BuildPlayer(string[] levels,string locationPathName , BuildTarget target ,BuildOptions options)levels :包括在build里的场景,如果空,当前打开的场景将被编译。路径是相对项目文件夹(Assets/MyLevels/MyScene.unity)
locationPathName:将被编译应用程序的路径,必须包括所有必要的文件扩展名
target:用于指定要编译的BuildTarget
options:额外的编译选项,多个选项可以组合在一起,例如是否运行那种播放器[MenuItem("Build/BuildWebplayer")]
static function MyBuild()
{var levels: String[]=["Asset/Scene1.unity","Asset/Scene2.unity"];BuildPipeline.BuildPlayer(levels,"WebPlayerBuild" , BuildTarget.WebPlayer,BuildOptions.None);
}

BuildAssetBundleOption选项
在创建AssetBundle文件的时候,Unity提供了若干个创建选项,每个选项的作用
None:
构建AssetBundle没有任何特殊的选项。

DisableWriteTypeTree:
在AssetBundle中不包含类型信息。但需要注意的事,如果将AssetBundle发布到Web平台上,则不能使用该选项

DeterministicAssetBundle
使每个Object具有唯一不变的hash ID ,可用于赠量式发布AssetBundle。

UncompressedAssetBundle
不进行数据压缩。如果使用该选项,因为没有压缩/解压缩的过程,AssetBundle的发布和加载会更快,但是AssetBundle也会更大,导致下载速度变慢

ForceRebuildAssetBundle
强制重新Build所有的AssetBundle

IngoreTypeTreeChanges
忽略TypeTree的变化,不能与DisableTypeTree同时使用。

AppendHashToAssetBundleName
附加Hash到AssetBundle名称中。

BuildTarget选项
目标的构建平台

  AssetBundle在不同平台之间是不完全兼容的,在多个独立平台构建的AssetBundle可以再这些平台上加载,但并不能在IOS和Android上加载,这需要单独指定他们的BuildTarget。此外,Android和IOS之间也不能相互兼容。

Unity处理Asset之间的依赖关系

Unity会自动处理Asset之间的依赖关系,并把这种依赖关系Build到AssetBundle之中,不再需要通过PopAssetDependencies()/PushAssetDenpencies()来处理依赖关系。

Unity提供了Manifest文件向用户展示这些依赖关系,在处理Assets的依赖关系时不再需要重新打包整个依赖链

1、Cube>Material>Texture
2、Cube.unity3d>material.unity3d
3、更新Material的Texture
4、只需重新打包,material.unity3d即可
在Editor模式下,Unity为每个AssetBundle都会生成一个Manifest文件,在Manifest文件中包含:
1、CRC
2、所包含的Assets
3、所依赖的AssetBundles
4、Hash
5、ClassTypes

AssetBundle Manifest提供了以下访问接口:
GetAllAssetBundles()
获得所有的AssetBundle的Manifest。

GetAllAssetBundlesWithVariant()
获取所有Variant的AssetBundles的Manifest

GetDependencies(string)
获取给定AssetBundle所依赖的AssetBundles。

GetAssetBundleHash(string)
获取给定AssetBundle的Hash。

GetDirectDependencies(string)
获取给定AssetBundle直接依赖的AssetBundles。

WWW wwwManifest = new WWW(manifestPath);
yield return wwwManifest;
AssetBundle manifestBundle = wwwManifest.assetBundle;
AssetBundleManifest manifest = (AssetBundleManifest)manifestBundle.LoadAsset("AssetBundleManifest");
manifestBundle.Unload(false);
string[] allAssetBundles = manifest.GetAllAssetBundles();
//assetBundleName为assetbundle名称.
string[] depedentAssetBundles =   manifest.GetAllDependencies(assetBundleName);

在对资源打包后,在输出的路径文件下会有一个总的manifest文件,文件名与所在的文件夹名称相同,然后每一个大包的资源分别会有一个自己的manifest文件。

Name:表示AssetBundle的名称
Dependencies:表示该AssetBundle所依赖的AssetBundle,如果内容为空,则说明该AssetBundle没有依赖的AssetBundle

如何下载AssetBundle

Unity引擎提供了两种方式来从服务器上动态下载AssetBundle文件
1、非缓存机制
通过创建一个WWW实例来对AssetBundle文件进行下载。下载后的AssetBundle文件将不会进如Unity引擎特定的缓存区

IEnumerator Start()
{//开始从指定的URL下载WWW www=new WWW(url);yield return www;
}

2、缓存机制
  通过WWW.LoadfromCacheorDownload接口来下载AssetBundle文件。下载后的AssetBundle文件将自动被存放在Unity引擎特定的缓存区,该方法是Unity推荐的AssetBundle文件下载方式。

  在下载AssetBundle文件时,该接口会先根据版本号在本地缓存区中查找该文件,看其之前是否被下载过。

  如果下载AssetBundle文件时,该接口会先根据版本号在本地缓存区中查找该文件,看其之前是否被下载过。如果下载过,则直接从缓存区将其读入进来;

  如果没有,则从服务器下进行下载。这中做法的好处是,可以节省AssetBundle文件的下载时间,从而提高游戏资源的载入速度
需要注意的是:
Unity提供的缺省缓存大小事根据发布平台的不同而不同的。
目前,对于发布到Web Player上的网页游戏,缓存缺省大小为50M
对于发布到PC上的客户端游戏和发布到IOS/Android上的移动游戏,缓存缺省大小为4G
开发商可以通过购买有Unity提供的Caching license来增大网页平台上的缓存大小,该授权可以极大地提供网页游戏的运行流畅度。

IEnumerator Start()
{//开始从指定的URL下载WWW www=WWW.LoadFromCacheOrDownload(url,5);//等待下载完成yield return www;}

AssetBundle的加载与卸载
如果加载AssetBundle
当AssetBundle文件从服务器下载到本地之后,需要将其加载到内存中并创建AssetBundle文件内存对象。

Unity提供了四种方式来加载AssetBundle文件:

1、WWW.asssetbundle属性
可以通WWW.asssetbundle属性来创建一个AssetBundle文件的内存对象。

IEnumerator Start()
{WWW www=WWW.LoadFromCacheOrDownload(url,5);yield return www;if(www.error!=null){Debug.Log(www.error);return;}AssetBundle myLoadedAssetBundle=www.assetBundle;
}

2、AssetBundle.CreateFormFile()
完整定义

public static AssetBundle CreateFromFile(string path)

  通过该接口可以从磁盘文件创建一个AssetBundle文件的内存对象。需要注意的是,该方法仅支持非压缩格式的AssetBundle,即在创建AssetBundle时必须使用UncompressedAssetBundle选项。

3、AssetBundle.CreateFromMemory()

public static AssetBundleCreateRequest CreateFromMemory(byte[] binary)

通过该接口可以创建一个异步AssetBundle内存区域。
比如当用户对AssetBundle进行加密时,可以先调用解密算法返回解密后的数据流,然后再通过AssetBundle.CreateFromMemory从数据流创建AssetBundle对象。

IEnumerator Start()
{//开始下载AssetBundlevar www=WWW.LoadFromCacheOrDownload(url ,5);//等待下载完成yield return www;//从bytes数组中创建AssetBundleAssetBundleCreateRequest assetBundleCreateRequest=AssetBundle.CreateFromMemory(www.bytes);yield return assetBundleCreateRequest;AssetBundle assetBundle=assetBundleCreateRequest.assetBundle;
}

4、AssetBundle.CreateFromMemoryImmediate

public static AssetBundle CreateFromMemoryImmediate(byte[] binary)

通过该接口可以同步创建一个AssetBundle内存区域

IEnumerator Start()
{WWW www = new WWW("http://myserver/myBundle.unity3d");yield return www;AssetBundle assetBundle = AssetBundle.CreateFromMemoryImmediate(www.bytes);
}

  需要注意的是:如果AssetBundle之间存在依赖关系,要先加载总的manifest文件,通过manifest文件加载对应的依赖文件,然后再加载要加载的AssetBundle。

public class LoadAssets:MonoBehavior
{//总的manifest文件名称public string manifestName="AssetBundles";//要加载的AssetBundle名称public string assetBundleName="test";IEnumerator Start(){//assetbundle所在的路径string assetBundlePath="file://"+Application.dataPath+"/AssetBundles";//manifest文件所在路径string manifestPath=AssetBundlePath+manifestName;//首先加载manifest文件WWW wwwManifest=WWW.LoadFromCacheOrDownload(manifestPath,0);yield return wwwManifest;if(wwwManifest.error==null){AssetBundle manifestBundle=wwwManifest.assetBundle;AssetBundleManifest manifest=(AssetBundleManifest)manifestBundle.LoadAsset("AsssetBundleManifest");manifestBundle.Unload(false);//获取依赖文件列表string[] depedentAssetBundles=manifest.GetAllDependenies(assetBundleName);AssetBundle[] abs=new AssetBundle[depedentAssetBundles.Length];for(int i=0;i<depedentAssetBundles.Length;i++){//加载所有的依赖文件WWW www=WWW.LoadFromCacheOrDownload(assetBundlePath+depedentAssetBundles[i],0);yield return www;abs[i]=www.assetBundle;}//加载需要的文件WWW www2=WWW.LoadFromCacheOrDownload(assetBundlePath+assetBundleName,0);yield return www2;AssetBundle assetBundle=www2.assetBundle;}else{Debug.Log(wwwManifest.error);}}
}

如何从AssetBundle中加载Assets
当AssetBundle文件加载完成后,就可以将所包含的Assets加载到内存中,Unity提供了六种加载API进行开发

AssetBundle.LoadAsset()
该接口可以通过名字来将AssetBundle文件中包含的对应Asset名称同步加载到内存中,也可以通过参数来指定加载Asset的类型
AssetBundle.LoadAllAsync()
该接口的作用与AssetBundle.LoadAsset相同,不同的是该接口是对Asset进行异步加载,即加载时主线程可以继续执行
AssetBundle.LoadAllAssets()
该接口用来一次性同步加载AssetBundle文件中的所有Assets,同AssetBundle.LoadAsset一样,可以通过指定加载Asset的类型来选择性地加载Assets。
AssetBundle.LoadAllAseetAsync()
该接口用来一次性异步加载AssetBundle文件中的所有Assets
AssetBundle.LoadAllAssetWithSubAssets()
该接口可以通过名字同步加载AssetBundle文件中的Assets的子Assets,同AssetBundle.LoadAsset一样,可以通过指定加载Asset的类型来选择性地加载Assets。

在Unity5后,不再支持直接Load组件类型,先试用Load游戏对象然后查找组件对象

IEnumerator Start()
{WWW www=WWW.LoadFromCacheOrDownload(url,1);yield return www;//取得AssetBundleAssetBundle bundle=www.assetBundle;//异步加载对象AssetBundleRequest request=bundle.LoadAssetAsync("myObject",typeof(GameObject));//等待异步完成yield return request;//获得加载对象的引用GameObject obj=request.asset as GameObject;//从内存中卸载AssetBundlebundle.Unload(false);//将没有使用的资源卸载
}

如何从场景AssetBundle中加载Assets

Application.LoadLevel
该接口可以通过名字或者索引载入AssetBundle文件中包含的对应场景。当加载新场景中,所有之前加载的GameObject都会被销毁
Application.LoadLevelAsync
该接口的作用与Application.LoadLevel相同,不同的是该接口是对场景进行异步加载,即加载时主线程可以继续执行
Application.LoadLevelAdditive
不同于Application.LoadLevel的是,它并不销毁之前加载的GameObject。
Application.LoadLevelAdditiveAsync
该接口的作用与Application.LoadLevelAdditive相同,不同的是该接口是对场景进行异步加载,即加载时主线程可以继续执行。
Application.LoadLevelAsync接口异步加载场景
public class LoadScenes:MonoBehaviour{//场景文件名字public string sceneAssetBundle;//场景名称public string sceneName;IEnumerator Start(){//场景AssetBundle路径string path="file://"+Application.dataPath+"/AssetBundles/"+sceneAssetBundle;WWW www=WWW.LoadFromCacheOrDownload(path,0);yield return www;if(www.error==null){AssetBundle ab=www.assetBundle;AsyncOperation async=Application.LoadLevelAsync(sceneName);yield return async;}else{Debug.Log(www.error);}}
}

AssetBundle Variant的使用

AssetBundle Variant通过AssetBundle用来实现Virtual Asset,和不同分辨资源的使用,最终达到在运行时动态替换AssetBundle。
AssetBundle名称相同但不同AssetBundle Variant的AssetBundle之间将有共同的内部id,所以它们之间可以任意切换。
用户可以通过AssetBundle的UI来设置
AssetImporter.assetBundleVariant:

AssetImporter assetImporter=new AssetImporter();
assetImporter.assetBundleVariant="hd";

AssetBundleBuild.assetBundleVariant:

AssetBundleBuild assetBundleBuild =new AssetBundleBuild();
assetBundleBuild.assetBundleVariant="sd";

AssetBundle Variant会用于AssetBundle的后缀名中

AssetImporter.assetBundleName="myassets";
assetBundleBuild.assetBundleVariant="hd";
最终AssetBundle name为"myassets.hd"

AssetBundle的内存管理
内存管理是游戏制作中非常重要的一步。
在这里插入图片描述

下载和加载AssetBundle时对内存的影响
1、AssetBundle文件的下载和加载
  在下载时可通过WWW或WWW.LoadfromCacheOrDownload方法从服务端或本地缓存区获得AssetBundle文件,并通过WWW.assetbundle属性加载AssetBundle对象。

Unity引擎在使用WWW方法时会分配一系列的内存空间来存放WWW实例以及Web stream数据。
  该数据包括原始的AssetBundle数据、解压后的AssetBundle数据以及一个用于解压的Decompression Buffer。
一般情况下,Decompression Buffer会在原始的AssetBundle完成解压后自动销毁。但需要主要的是,Unity内部会自动保留一个Decompression Buffer,使其不被系统回收。

例如当同时加载3个AssetBundle时,那么系统会生成3个Decompression Buffer并同时对每个AssetBundle进行解压,当解压完成后,系统会自动销毁其中的2个Decompression Buffer,而留下一个Decompression Buffer,以备下次解压缩AssetBundle时复用。这样的做的好处是,不用过于频繁地开辟和销毁解压Buffer,从而可以在一定程序上降低CPU的小孩

2、资源转换和实例化
  当把AssetBundle解压并加载到内存后,开发者可以通过从WWW.assetbundle属性所获得的AssetBundle对象来得到各种Asset,并对这些Assets进行加载或实例化操作。
  加载过程中,Unity会将AssetBundle中的数据流转变成引擎可识别的信息类型(纹理、材质、对象等)。加载完成后,开发者即可对其进一步的操作,比如对象的实例化、纹理和材质的复制、替换等。

AssetBundle以及Asset的卸载
无论是在下载和加载过程中,还是在Asset加载和实例化过程中,AssetBundle以及由其加载的Assets均会占用内存。

1、AssetBundle的卸载
通过AssetBundle.Unload接口卸载AssetBundle自身
2、从AssetBundle加载的Assets的卸载
对于从AssetBundle加载的Asset,比如纹理、材质、音频片段和动画片段等,有两种方式进行卸载

Assetbundle.Unload(true)
该接口会强行卸载掉所有AssetBundle中加载的Assets,不推荐使用这种方式卸载Assets

Resources.UnloadUnusedAssets()
该接口会卸载掉所有没有使用的Assets,需要强调的是,它的作用范围不仅是当前的AssetBundle,而是整个系统,而且它也不能卸载掉从当前AssetBundle文件中加载的仍在使用的Assets

  对于由GameObject.Instantiate接口实例化除的GameObject,Unity提供了GameObject.Destory或GameObject.DestroyImmediate接口来讲其卸载。Unity推荐使用GameObject.Destroy接口,如果使用该接口,Unity会将真正的删除操作延后到一个合适的时机统一进行处理,但是会在渲染之前进行。

WWW、AssetBundle以及Asset的关系

在这里插入图片描述
WWW对象和通过WWW.assetbundle属性所加载的AssetBundle对象会对Web Stream数据持有引用,同时AssetBundle也会引用到从它所加载的所有Asset。
值得一提的事,真正的数据都是存放Web Stream数据中,例如纹理、模型等,而WWW和AssetBundle对象只是一个结构指向了Web Stream数据

对于WWW对象本身,可以使用www=null或WWW.dispose来进行卸载。二者的效果一样,只是www=null
不会及时引起内存释放操作,而是在系统自动垃圾回收时进行释放;而WWW.dispose会及时调用系统的垃圾回收操作来进行内存释放。
WWW对象释放后,其对于Web Stream数据的引用计数也会相应减1.

对于Web Stream数据,其所占用的内存会在其引用计数为0时,自动被系统进行释放
AssetBundle对象以及WWW对象被释放后,Web Stream数据所占用的内存也会被系统自动回收

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/799977.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习】移动端App性能测试流程有哪些

移动端App性能测试是保证App性能表现的重要环节之一。随着移动设备的普及和移动互联网的发展&#xff0c;移动端App的性能测试变得越来越重要&#xff0c;通过科学合理的性能测试可以发现并解决潜在的性能问题优化App运行效果提高用户体验。性能测试旨在评估App在各种场景下的性…

基于视频监管与AI智能识别技术的水利河道综合治理解决方案

一、方案介绍 TSINGSEE青犀视频水利河道综合治理解决方案是依托视频AI智能分析技术&#xff0c;利用水质/水文等传感器、高清摄像机、水利球、无人机、无人船等感知设备实时采集数据&#xff0c;并与视频能力进行联动&#xff0c;达到智能预警的目的。 TSINGSEE青犀方案以信息…

Spring Cloud微服务入门(三)

服务注册与发现的概念 服务之间相互访问&#xff1a; 例如&#xff1a;用户中心与内容中心之间相互调用。 问题&#xff1a; 服务调用需要知道对方的服务地址&#xff0c;地址写在哪里&#xff1f; 如果服务是多个实例部署&#xff0c;该调用哪一个&#xff1f; 如果服务是多…

Jetpack Compose -> 状态机制的背后秘密

前言 上一章我们讲解了 Jetpack Compose 的无状态、状态提升、单向数据流 本章我们讲解下状态机制的背后秘密 List 前面我们讲过&#xff0c;通过 by mustableStateOf() 就可以被 Compose 自动订阅了&#xff1b;我们前面是通过 String 类型进行的自动订阅&#xff0c;那么换成…

【深度学习】YOLO-World: Real-Time Open-Vocabulary Object Detection,目标检测

介绍一个酷炫的目标检测方式&#xff1a; 论文&#xff1a;https://arxiv.org/abs/2401.17270 代码&#xff1a;https://github.com/AILab-CVC/YOLO-World 文章目录 摘要Introduction第2章 相关工作2.1 传统目标检测2.2 开放词汇目标检测 第3章 方法3.1 预训练公式&#xff1a…

电容隔离型±10V输入隔离放大器特点:ISOC 124P

产品特点: 50KHz(-3dB)高带宽与ISO 124P隔离器Pin-Pin兼容 低成本小体积&#xff0c;标准DIP16Pin阻燃材料封装 精度等级:0.01级&#xff0c;全量程内非线性度0.01% 信号输入与输出之间:3000VDC隔离耐压 电源范围:4.5V~18V 双极运算:Vo10V 方便易用&#xff0c;固定单位增益配置…

ubuntu安装nginx以及开启文件服务器

1. 下载源码 下载页面&#xff1a;https://nginx.org/en/download.html 下载地址&#xff1a;https://nginx.org/download/nginx-1.24.0.tar.gz curl -O https://nginx.org/download/nginx-1.24.0.tar.gz2. 依赖配置 sudo apt install gcc make libpcre3-dev zlib1g-dev ope…

【分治算法】Strassen矩阵乘法Python实现

文章目录 [toc]问题描述基础算法时间复杂性 Strassen算法时间复杂性 问题时间复杂性Python实现 个人主页&#xff1a;丷从心. 系列专栏&#xff1a;Python基础 学习指南&#xff1a;Python学习指南 问题描述 设 A A A和 B B B是两个 n n n \times n nn矩阵&#xff0c; A A…

CICD流水线 发布应用到docker镜像仓库

准备工作 1.先注册免费的镜像仓库 复制链接: https://cr.console.aliyun.com/cn-beijing/instances 实施 1. 新建流水线&#xff0c;选择模板 2.添加流水线源&#xff0c;及是你的代码仓库, 选择对应分支. 3.代码检查以及单元测试&#xff0c;这个步骤可以不用动它. 4. …

AI的力量感受(附网址)

输入 科技感的 二维码&#xff0c;生成如下&#xff0c;还是可以的 输入金属感 的芯片&#xff0c;效果就很好了 金属感 打印机&#xff0c;细节丰富&#xff0c;丁达尔效应 就有点跑题了 金属感 扫码仪 还有点像 3D 封装长这样&#xff0c;跑题比较严重 总之&#xff0c;AI还…

如何使用生成式人工智能撰写关于新产品发布的文章?

利用生成式人工智能撰写新产品发布文章确实是一种既有创意又高效的内容生成方式。以下是如何做到这一点的指南&#xff0c;附带一些背景信息&#xff1a; • 背景&#xff1a;在撰写文章之前&#xff0c;收集有关您的新产品的信息。这包括产品的名称、类别、特点、优势、目标受…

朗汀留学美国生物医学工程专业留学部分录取案例合集

满怀期待的憧憬与金榜题名的喜悦交织着未来的掌声&#xff0c;捧在手心里的不仅仅是一份一份努力浇灌的录取通知&#xff0c;更是一起拼搏走过的岁月沉淀。 我们感恩每一位朗汀留学的学生和家长&#xff0c;是你们的支持与信任&#xff0c;让我们有机会共享此刻的荣耀&#xff…

数据挖掘及其近年来研究热点介绍

&#x1f380;个人主页&#xff1a; https://zhangxiaoshu.blog.csdn.net &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️&#xff0c;如有错误敬请指正! &#x1f495;未来很长&#xff0c;值得我们全力奔赴更美好的生活&…

jdk目录结构

jdk目录详解 JDK(Java Development Kit&#xff0c;Java开发包&#xff0c;Java开发工具)是一个写Java的applet和应用程序的程序开发环境。它由一个处于操作系统层之上的运行环境还有开发者 编译&#xff0c;调试和运行用Java语言写的applet和应用程序所需的工具组成。 JDK(J…

【数据结构】考研真题攻克与重点知识点剖析 - 第 6 篇:图

前言 本文基础知识部分来自于b站&#xff1a;分享笔记的好人儿的思维导图与王道考研课程&#xff0c;感谢大佬的开源精神&#xff0c;习题来自老师划的重点以及考研真题。此前我尝试了完全使用Python或是结合大语言模型对考研真题进行数据清洗与可视化分析&#xff0c;本人技术…

爱普生语音芯片的特点与应用市场

随着物联网与智能家居的普及&#xff0c;越来越多的电子产品有了语音播报的需求。但是很多客户没有类似的开发经验或者他们的产品内部只能承载一个蜂鸣器。这样的情况下要如何实现快速的产品升级呢?下面让我们来看一下差普生语音芯片是如果帮助客户的。目前爱普生语音芯片分为…

Redis 的主从复制、哨兵和cluster集群

目录 一. Redis 主从复制 1. 介绍 2. 作用 3. 流程 4. 搭建 Redis 主从复制 安装redis 修改 master 的Redis配置文件 修改 slave 的Redis配置文件 验证主从效果 二. Redis 哨兵模式 1. 介绍 2. 原理 3. 哨兵模式的作用 4. 工作流程 4.1 故障转移机制 4.2 主节…

记录一次内网渗透过程

0x01 前言&#xff1a; 一切以学习为主&#xff0c;记录一次小小的攻击过程 本次是通过外网漏洞撕开的口子&#xff0c;主要通过一下方式 拿到了目标资产 nday扫一扫 弱口令爆一爆 上传接口找一找 后台上传找一找 数据库弱口令 关注新day&#xff0c;有了立马在资产里面…

K8s学习三(Pod与探针)

深入学习Pod Pod配置文件 写一个自己的配置文件,nginx-po.yaml apiVersion: v1 #api文档版本 kind: Pod #资源类型对象&#xff0c;也可以配置为像Development&#xff0c;StatefulSet这一类的对象 metadata: # Pod相关的元数据&#xff0c;用于描述Pod的数据name: nginx-po…

深度比较Vue 3.0中的computed和watch属性用法与最佳实践

摘要&#xff1a;在Vue 3.0中&#xff0c;computed和watch属性是用于处理数据逻辑的重要工具。本文将详细对比这两个属性的工作原理、适用场景以及使用时的注意事项&#xff0c;旨在帮助开发者更有效地选择和使用它们。 一、computed属性 computed属性是Vue 3.0中用于计算数据…