您的位置:首页 > 移动开发 > Unity3D

Unity笔记 资源加载 内存优化

2015-07-15 13:55 701 查看
本机堆(Native Heap)

这里是unity管理的资源内存(区别于c#的托管堆),包括装载GameObject, Transform, Mesh, Texture, Material, Shader和Script等。这些内存是unity来管理的,看下unity默认如何组织的资源加载和卸载的。但是否和托管堆是独立的这个有待验证。

加载,当scene加载完成时所有用到的asset都会被加载,包括Hierarchy中的所有的gameobject涉及的资源和脚本中用到的资源。

卸载,除了DontDestroyOnLoad的资源,在切换scene时都会被卸载。注意singleton(设计模式)通常用到DontDestroyOnLoad。

对于内存优化,我们感兴趣的就是看看什么行为可以影响unity自己的资源加载和卸载策略。

尽量减少Hierarchy中的引用,改成手动的Resource.Load()这样加载的资源可以用Resource.UnloadAsset(obj)和Resources.UnloadUnusedAssets()来释放。还有AssetBundle的Load和Unload方法。

这些load和unload还有Instantiate都是干啥的,见下图:



看了上图,可以理解加载的2个阶段:第一阶段是使用Resources.Load或者AssetBundle.Load加载各种资源,第二阶段是使用GameObject.Instantiate克隆出一个新的GameObject。

3种实例化prefab的方式

1)Resouce.Load,再调用Instantiate

2)AssetBundle.Load,再调用Instantiate

3) 在Inspector里把prefab拖到一个public变量上去,用的时候调用Instantiate

只有AssetBundle.Load的方式不会导致第一次实例化(Instantiate)的延迟。

使用Resources.Load的时候在第一次Instantiate之前,相应的Asset对象还没有被创建,直到第一次Instantiate时才会真正去读取文件创建这些Assets。它的目的是实现一种OnDemand的使用方式,到该资源真正使用时才会去创建这些资源。

而使用AssetBundle.Load方法时,会直接将资源文件读取出来创建这些Assets,因此第一次Instantiate的代价会相对较小。

UnusedAssets

如何让一个gameobject可以通过UnloadUnusedAssets释放。

Object obj = Resource.Load("MyPrefab");
GameObject instance = Instantiate(obj) as GameObject;
Destroy(instance);

Resources.UnloadUnusedAssets();// 这里不会释放内存

obj = null;

Resources.UnloadUnusedAssets();// 这里会释放内存


再结合图看一遍这些操作

Instantiate的过程是一个对Assets进行Clone(复制)和引用相结合的过程,Clone的过程需要申请内存存放自己的数据,而引用的过程只需要直接一个简单的指针指向一个已经Load的资源即可。例如Transform是通过Clone出来的,Texture和TerrainData是通过引用复制的,而Mesh,Material,PhysicalMaterial和Script是Clone和引用同时存在的(换句话说,gameobject需要自己数据的就要clone,不需要的引用就好了)。

因此Load操作其实Load一些原型数据(Assets)出来,用于创建新对象时被Clone或者被引用。

然后是销毁资源的过程。当Destory一个GameObject或者其他实例时,只是释放实例中那些Clone出来的Assets,而并不会释放那些引用的Assets,因为Destroy不知道是否有其他人在引用这些Assets。等到场景中没有任何物体引用到这些Assets之后,它们就会成为UnusedAssets,此时可以通过Resources.UnloadUnusedAssets来进行释放。AssetBundle.Unload(false)不行,因为它只会释放文件的内存镜像,不会释放资源;AssetBunde.Unload(true)也不行,因为它是暴力的释放,可能有其他对象在引用其中的Assets,暴力释放可能导致程序错误。

另外需要注意,系统在加载新场景时,所有的内存对象都会被自动销毁,这包括了Resources.Load加载的Assets, 静态绑定的Assets,AssetBundle.Load加载的资源和Instantiate实例化的对象。但是AssetBundle.Load本身的文件内存镜像(用于创建各种Asset)不会被自动销毁,这个必须使用AssetBundle.Unload(false)来进行主动销毁。推荐的做法是在加载完资源后立马调用AssetBunble.Unload(false)销毁文件内存镜像。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity 内存优化