原创链接:http://blog.csdn.net/ox_thedarkness/article/details/9197453

分离资源管理

参考

1.Unity3D占用内存太大的解决方法 - 星尘

讨论AssetBundle-Resources-GameObject 的生命周期问题。对AssetBundle.Unload,Instantiate,Destory,UnloadUnusedAsset有详细的辨析。

http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html

讨论基于Unity3d 4.1.5,不定时更新。

基本信息

美术资源应导出为AssetBundle文件。这种AssetBundle有两种存储方式:可以是未压缩的,也可以使用7z算法压缩,默认压缩。以我手头的一个蒙皮动画角色为例,压缩后文件大小由800K减少到260K。导出过程中各个成分占的文件比例会在Logs中打印出来,以供分析和优化。
AssetBundle有下面两个主要的加载方法:

  • AssetBundle.CreateFromFile只能加载未压缩的文件。根据文档的说法,该方法是最快的加载方法,但是不知道这个"fast"是指“performace”还是"easy"。如果该算法是流式加载,可能确实是最快的,因为其他加载方法都有中间产物,例如CreateFromMemory或者WWW需会产生额外的byte[]。
  • AssetBundle.CreateFromMemory异步加载内存中二进制字节。这带来的好处是,硬盘上的文件可以使用自定义的方式组织、压缩和打包。

性能和内存泄露

加载过程中会产生三级中间产物:

  1. AssetBundle
  2. Asset-Object:所有AssetBundle.Load*创建的Object,包括mainAsset
  3. Cloned-Object:Instantiate一个Asset-Object之后产生的Object

其中,AssetBundle是资源的静态二进制存档形式。此时资源并没有真正读出,只有执行Load操作资源才会被创建到Resouces系统中。Resources系统管理Asset-Object亦即实际的资源,包括贴图、mesh、Asset-GameObject。其中的Asset-GameObject非常类似Cloned-GameObject,但是无法挂载到场景中,无法被Destroy销毁,只能用Instantiate生成Cloned-Object。实际我们看见的是Cloned-Object。

1. AssetBundle需要手工管理

Unity3d并没有追踪每个资源的来源。假如你反复加载同一个资源文件,每次AssetBundle.CreateFromFile/Memory都会创建一个新的AssetBundle,包含新的贴图、新的模型。为了减少这类误用,Unity在每个资源包的二进制内容中添加了一个随机包标志(包标志是导出时添加的,即使是同一个资源,每次导出都是不同的包)。Unity3d通过比较包标志的方式,禁止同时存在两个读取了相同资源包。若一个资源包对应的AssetBundle没有Unload,再次创建新的该资源的AssetBundle时会抛出错误:

  • The asset bundle '<unknown>' can't be loaded because another asset with the same files are already loaded

但是Unity只是简单在AssetBundle创建时做了检查,在Asset-Object级没有记录包标志来源,也不会合并相同资源。

  • 有一种不良做法:每次都重新读取资源包之后立即释放包,将Instantiate出来的角色放在场景上。这种做法很简洁不会引起内存泄漏,但是对于mmo rpg而言,场景上经常会有很多相同角色。每次重新读取的资源包都会产生独立的Asset-Object,结果就是场景上的20只史莱姆会拥有20份骨骼、20份贴图、20份材质、占用20份显存。

总的来说,项目框架需要手工管理AssetBundle,保证同一套资源不重复加载。

2. Asset-Object和Cloned-Object管理

所有AssetBundle.Load*加载的UnityEngine.Object,我们称为Asset-Object,与Instantiate创造出的 Cloned-Object相对应。

这两个概念在[1]的第一张配图中分别标记为”Asset-*“和”*-复制“。对成员mainAsset的访问实际上是完整的加载函数调用,为手工调用Load的简化版。另外经测试,反复Load同一个资源至少没有额外资源泄露。

在Unity自带的Profile系统中,Memory栏下 Textures/Meshes/Materials/AnimationClips/AudioClips指的就是Asset-Object。例如,从一个史莱姆Instantiate出很多史莱姆并不会增加Textures或者Meshes计数。

虽然都是UnityEngine.Object,但是Asset-Object和Cloned-Object本质是不同的。例如,如果对Asset-Object执行Destroy,系统会报错:

  • Destroying assets is not permitted to avoid data loss.

Asset-Object是由Resources系统管理的,包括Asset中的Texture、AnimationClips等,为内存开销的主要来源。Resources系统使用弱引用管理Asset-Object,同时提供了Resources.UnloadUnusedAsset()以删除没有不再被强引用的Asset-Object。注意他检查的是所有强引用,并不限于场景中实际GameObject,所以如果你的代码中记录了的Asset表,还有某些代码的意外引用都会阻止这些资源被Resources系统释放。

  • 有一种错误理解:我们只需要AssetBundle.Unload(false),然后在删除场景内容时Object.Destroy(),这样是否就没有泄漏了?答案是否定的,前者删除了AssetBundle,后者删除了Cloned-Object,但是Asset-Object还没有删除。Asset-Object由Resources系统管理,需要手工调用Resources.UnloadUnusedAsset()或者其他类似接口才能删除。

3. 场景管理

导出场景只能用BuildStreamedSceneAssetBundle,不能使用BuildAssetBundle。场景文件仍然可以用CreateFromMemory读取,只不过Clone的时候必须使用Application.LoadLevel。而且LoadLevel过程和结果貌似不可控,比如你从程序上并不能得到“场景加载完毕”或者“场景的内容是什么”这样的信息。

Unity3d资源管理分析的更多相关文章

  1. Unity3D管网分析

    给大家分享一下自己之前没事写的Unity3D的插件,主要用来对管网的搭建和分析, 开源在Github上 https://github.com/LizhuWeng/PipeNet,可以给需要的朋友做一个 ...

  2. Unity3D - 资源管理

    一直没有总结过Unity的资源管理,都是随用随看文档.今天有人问起,总结一下.加深对Unity资源管理的理解. 主要參考了Unity官方文档之Resources和AssetBundle. Unity有 ...

  3. Unity3D资源管理架构

    在Unity3D引擎中,场景资源文件(.unity)是以2进制格式存储的.但同一时候它也有一种基于文本的表现格式. 可在Edit>Project Setting>Editor 中设置: 1 ...

  4. 资源 Des加密

    Unity3d资源管理分析 http://blog.csdn.net/sgnyyy/article/details/39268215 打包资源 http://www.cnblogs.com/sifen ...

  5. c++内存分配

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

  6. C++内存管理(超长,例子很详细,排版很好)

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

  7. (转)从内存管 理、内存泄漏、内存回收探讨C++内存管理

    http://www.cr173.com/html/18898_all.html 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟 ...

  8. C++内存管理(超长)

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

  9. C++内存管理(转)http://www.cnblogs.com/qiubole/archive/2008/03/07/1094770.html

    [导语] 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的检查代码和对C++的痛恨,但内存管理在C++中无处不 ...

随机推荐

  1. (转)C# WebApi 身份认证解决方案:Basic基础认证

    原文地址:http://www.cnblogs.com/landeanfen/p/5287064.html 阅读目录 一.为什么需要身份认证 二.Basic基础认证的原理解析 1.常见的认证方式 2. ...

  2. selenium在scrapy中的应用

    引入 在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值.但是通过观察我们会发现 ...

  3. 初学Jmeter添加Http请求,执行接口测试

    最近测试并发,刚开始使用的是录制方法,后面发现录制后无任何界面,加参数也不知从何着手,于是查了很多文章,终于慢慢的着手从http请求来测试并发了. 当然这是个遗留问题,先放在这里后面清楚了再回来补充: ...

  4. Python笔记:用for循环删除列表中的元素

    for运行过程中会有一个指针来记录当前循环的元素是哪一个,一开始这个指针指向第0个元素,然后获取它,接着删除第0个元素,这时候,原来是第1个的元素会变成第0个,当指针向后移动一次,指向了现在第1个元素 ...

  5. this 基础使用方法

    在Java中,this是调用类中变量和内部类的构造方法的关键词,在对象有同名变量时,可以指定类的变量. 例子1: package example_1; import java.lang.*; publ ...

  6. mysql如何修改root用户的密码

    方法1: 用SET PASSWORD命令 首先登录MySQL. 格式:mysql> set password for 用户名@localhost = password('新密码'); 例子:my ...

  7. 序列化 (实现RPC的基础)

    public interface ISerializer { <T> byte[] serializer(T obj); <T> T deSerializer(byte[] d ...

  8. Linux 虚拟机的安全加固建议

    1.修改用户的密码口令策略:   [root@centos-73-1 chpaadmin]# cat /etc/login.defs |grep -i pass # passwd command) s ...

  9. Shell 编程(实例二)

    创建一个脚本,为指定硬盘创建分区 1.列出当前系统所有磁盘,让用户选择,如果选择quit则退出脚本:如果选择错误,则重新选择 2.当用户选择完成后,询问是否继续 3.抹除选择磁盘上的分区,为其创建三个 ...

  10. SonarQube与Jenkins结合提高代码质量

    首先,为什么需要SonarQube? 1.WriteClean Code 1)全局健康报告  2)关注新增的问题  3)强制QualityGate 4)Issue详情及建议- 详情参考:https:/ ...