unity内存加载和释放

Unity几种动态加载Prefab方式的差异:

其实存在3种加载prefab的方式:

一是静态引用,建一个public的变量,在Inspector里把prefab拉上去,用的时候instantiate

二是Resource.Load,Load以后instantiate

三是AssetBundle.Load,Load以后instantiate

三种方式有细节差异,前两种方式,引用对象texture是在instantiate时加载,而assetBundle.Load会把perfab 的全部assets都加载,instantiate时只是生成Clone。所以前两种方式,除非你提前加载相关引用对象,否则第一次 instantiate时会包含加载引用类assets的操作,导致第一次加载的lag。官方论坛有人说Resources.Load和静态引用是会把所 有资源都预先加载的,反复测试的结果,静态引用和Resources.Load也是OnDemand的,用到时才会加载。

几种AssetBundle创建方式的差异:

CreateFromFile:这种方式不会把整个硬盘AssetBundle文件都加载到内存来,而是类似建立一个文件操作句柄和缓冲区,需要时 才实时Load,所以这种加载方式是最节省资源的,基本上AssetBundle本身不占什么内存,只需要Asset对象的内存。可惜只能在PC/Mac Standalone程序中使用。

CreateFromMemory和www.assetBundle:这两种方式AssetBundle文件会整个镜像于内存中,理论上文件多大就需要多大的内存,之后Load时还要占用额外内存去生成Asset对象。

什么时候才是UnusedAssets?

看一个例子:

Object obj = Resources.Load("MyPrefab");

GameObject instance = Instantiate(obj) as GameObject;

.........

Destroy(instance);

创建随后销毁了一个Prefab实例,这时候 MyPrefab已经没有被实际的物体引用了,但如果这时:

Resources.UnloadUnusedAssets();

内存并没有被释放,原因:MyPrefab还被这个变量obj所引用

这时候:

obj = null;

Resources.UnloadUnusedAssets();

这样才能真正释放Assets对象

所以:UnusedAssets不但要没有被实际物体引用,也要没有被生命周期内的变量所引用,才可以理解为 Unused(引用计数为0)

所以所以:如果你用个全局变量保存你Load的Assets,又没有显式的设为null,那在这个变量失效前你无论如何 UnloadUnusedAssets也释放不了那些Assets的。如果你这些Assets又不是从磁盘加载的,那除了 UnloadUnusedAssets或者加载新场景以外没有其他方式可以卸载之。

一个复杂的例子,代码很丑陋实际也不可能这样做,只是为了加深理解

IEnumerator OnClick()
{
Resources.UnloadUnusedAssets();//清干净以免影响测试效果
yield return new WaitForSeconds(3);
float wait = 0.5f;
//用www读取一个assetBundle,里面是一个Unity基本球体和带一张大贴图的材质,是一个Prefab
WWW aa = new WWW(@"file://SpherePrefab.unity3d");
yield return aa;
AssetBundle asset = aa.assetBundle;
yield return new WaitForSeconds(wait);//每步都等待0.5s以便于分析结果
Texture tt = asset.Load("BallTexture") as  Texture;//加载贴图
yield return new WaitForSeconds(wait);
GameObject ba = asset.Load("SpherePrefab") as  GameObject;//加载Prefab
yield return new WaitForSeconds(wait);
GameObject obj1 = Instantiate(ba) as GameObject;//生成实例
yield return new WaitForSeconds(wait);
Destroy(obj1);//销毁实例
yield return new WaitForSeconds(wait);
asset.Unload(false);//卸载Assetbundle
yield return new WaitForSeconds(wait);
Resources.UnloadUnusedAssets();//卸载无用资源
yield return new WaitForSeconds(wait);
ba = null;//将prefab引用置为空以后卸无用载资源
Resources.UnloadUnusedAssets();
yield return new WaitForSeconds(wait);
tt = null;//将texture引用置为空以后卸载无用资源
Resources.UnloadUnusedAssets();
}

这是测试结果的内存Profile曲线图

很经典的对称造型,用多少释放多少。

这是各阶段的内存和其他数据变化

说明:

1 初始状态

2 载入AssetBundle文件后,内存多了文件镜像,用量上升,Total Object和Assets增加1(AssetBundle也是object)

3 载入Texture后,内存继续上升,因为多了Texture Asset,Total Objects和Assets增加1

4 载入Prefab后,内存无明显变化,因为最占内存的Texture已经加载,Materials上升是因为多了Prefab的材质,Total Objects和Assets增加6,因为 Perfab 包含很多 Components

5 实例化Prefab以后,显存的Texture Memory、GameObjectTotal、Objects in Scene上升,都是因为实例化了一个可视的对象

6 销毁实例后,上一步的变化还原,很好理解

7 卸载AssetBundle文件后,AssetBundle文件镜像占用的内存被释放,相应的Assets和Total Objects Count也减1

8 直接Resources.UnloadUnusedAssets,没有任何变化,因为所有Assets引用并没有清空

9 把Prefab引用变量设为null以后,整个Prefab除了Texture外都没有任何引用了,所以被UnloadUnusedAssets销毁,Assets和Total Objects Count减6

10 再把Texture的引用变量设为null,之后也被UnloadUnusedAssets销毁,内存被释放,assets和Total Objects Count减1,基本还原到初始状态

从中也可以看出:

Texture加载以后是到内存,显示的时候才进入显存的Texture Memory。

所有的东西基础都是Object

Load的是Asset,Instantiate的是GameObject和Object in Scene

Load的Asset要Unload,new的或者Instantiate的object可以Destroy

时间: 2024-10-11 22:23:41

unity内存加载和释放的相关文章

内存加载DLL

1.前言 目前很多敏感和重要的DLL(Dynamic-link library) 都没有提供静态版本供编译器进行静态连接(.lib文件),即使提供了静态版本也因为兼容性问题导致无法使用,而只提供DLL版本,并且很多专业软件的授权部分的API,都是单独提供一个DLL来完成,而主模块通过调用DLL中的接口来完成授权功能.虽然这些软件一般都采用了加壳和反调试等保护,但是一旦这些功能失去作用,比如脱壳,反反调试,HOOK API或者干脆写一个仿真的授权DLL(模拟授权DLL的所有导出函数接口),然后仿真

Android中apk加固完善篇之内存加载dex方案实现原理(不落地方式加载)

一.前言 时隔半年,困扰的问题始终是需要解决的,之前也算是没时间弄,今天因为有人在此提起这个问题,那么就不能不解决了,这里写一篇文章记录一下吧.那么是什么问题呢? 就是关于之前的一个话题:Android中apk加固技术实现 关于这个问题,之前的一篇文章已经说过了,没有了解的同学可以点击这里:Android中apk加固技术实现 请务必仔细的看完这篇文章,不然今天说的内容会感觉很蛋疼的,因为今天的文章就是为了解决当初的加固技术遗留的问题,这里先大致来说一下加固apk的原理吧,先来看一张图: 看到这张

打造DLL内存加载引擎学习笔记

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题 首先看下我们内存加载引擎的流程. 1. 申请一段大小为dll映射内存后的映像大小的内存空间. 2. 移动各个区段的数据到申请的内存. 2. 修复引入表结构的地址表. 4. 通过重定位结构修复需要重定位的地址. 5. 调用DllMain入口点 流程解析: pe结构中nt header结构当中的ImageSize存放的是我们整个文件映射到内存后的映像大小,这

看起来很懵的java内存加载面试

java内存加载机制一直以为掌握的还不错,今天被考验到了,一时间竟然很懵 http://p.baidu.com/itopic/main/qlog?qid=d5236162636533646239363600&type=questionloghttp://p.baidu.com/itopic/main/qlog?qid=db236162636332613639663600&type=questionloghttp://p.baidu.com/itopic/main/qlog?qid=e023

unity 场景加载和对象消失的几种方法

场景加载: Application.LoadLevel(Application.loadedLevel); // 重新调用场景 Application.LoadLevel(0); // 调用你在设置里摆放的场景,按你的摆放顺序调 场景加载后保留当前指定的对象,留到下一个场景: DontDestroyOnLoad (transform.gameObject); 结束游戏: Application.Quit() ; gameObject.renderer.enabled //是控制一个物体是否在屏幕

[javase学习笔记]-7.4 构造函数的内存加载

这一节我们来说说构造函数在内存中是如何被加载的. 我们之前说过,构造函数只有创建对象时才会被调用并且只调用一次.那么在创建对象的过程中内存中的变化是什么样的呢? 我们接着上一节的Person类,我们分析 class Person { private String name; private int age; Person()//构造函数,分别为成员变量name和age赋固定的值 { name = "baby"; age = 1; System.out.println("per

Unity的加载路径

1.Resources 路径 只读 不能动态的修改 存放内容 预制体(prefabs) - 不容易变化的预制体 prefabs打包的时候 会自动过滤不需要的资源 有利于减小资源大小 主线程加载 Resources类的Load方法 文件夹中的内容打包的时候会被压缩和加密 2.streamingAssetsPath 内容会原封不动的打入包中 一般建议存放一些二进制文件 (配置文件,unity资源包(AB文件)等) 特点 只读 不可写 主要存放二进制文件 通过WWW类 读取文件(移动端) 3.pers

很考验人的java内存加载面试题

源代码如下,求结果 public class MemoryAnalyse { public static int k = 0; public static MemoryAnalyse t1 = new MemoryAnalyse("t1"); public static MemoryAnalyse t2 = new MemoryAnalyse("t2"); public static int i = print("i"); public stat

Unity资源加载路径及加载方式小结

Unity3D中的资源路径路径属性 路径说明Application.dataPath 此属性用于返回程序的数据文件所在文件夹的路径.例如在Editor中就是Assets了.Application.streamingAssetsPath 此属性用于返回流数据的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径.放在Unity工程StreamingAssets文件夹中的资源发布后都可以通过这个路径读取出来.Application.persistentDataPath 此属性用于返回一个持久