从Profile中窥探Unity的内存管理
刨根问底U3D---从Profile中窥探Unity的内存管理
这篇文章包含哪些内容
这篇文章从Unity的Profile组件入手,来探讨一下Unity在开发环境和正式环境中的内存使用发面的一些区别,
并且给出了最好控制内存的方法(我想你已经知道了...Prefab ) ,以及原因。
提前需要阅读的文章
在阅读本文之前或之后我建议阅读一下以下几篇文章
雨松的
Unity3D研究院之Assetbundle的实战 http://www.xuanyusong.com/archives/2405/
Unity3D研究院之Assetbundle的原理 http://www.xuanyusong.com/archives/2373
王巍的
Unity 3D中的内存管理 http://onevcat.com/2012/11/memory-in-unity3d/
星尘(不太确定是否是原作者 哈)的
Unity3D占用内存太大的解决方法 http://www.cnblogs.com/88999660/archive/2013/03/15/2961663.html
从NGUI的AltasPacker说起
事情的起因还是因为我在学习使用NGUI(刚接触Unity没几天…), 教程看了看都没问题 自己动手操作的时候突然发现...
NGUI 创建UI时候必须都先要创建Altas,那我创建好后的散图是放在工程里面呢 还是要删掉? 不删会影响性能么?
Google了一番并没有发现满意答案,所以只好自己Profile一下,于是有了如下实验:
1· 首先建立一个空场景,运行,打开Profile. Texture(纹理)部分使用内存2.5MB

2·加入一张图片,场景上不做任何引用。 该图片显存展开后大小为1.5MB , 运行 然后再打开Profile

3· 奇迹的事情发生了... 纹理占用的内存大小直接变为 5.8MB

5.8MB- 2.5MB = 3.3MB 很奇怪的一个数,于是我同时怀疑三件事
1· 即使素材完全用不到但是如果工程中有导入则最后会被打包
2· 即使素材没有被当前场景使用,Unity仍旧会加载 ( Unity启动时候加载所有的素材??! )
3· Unity对素材在内存中有留有一份引用,3.3MB ~= 1.5MBx2 ( ??! )
如果以上三点有一个是真的(全是错的), 那Unity无疑直接变为废柴....
于是乎就此三点我开始无限的刨根问底....
功夫不负有心人吧,终于在一片帖子上面找到了突破口
http://answers.unity3d.com/questions/57909/find-unused-assets-in-project.html
这篇文章说的很清楚,Unity在发布时候会自动过滤掉未引用的所有资源,并且整个被打包进来的资源可以通过Log查看
根据文章指出的位置找到Log,并且就上面的工程进行测试,打出Android包 (Mac下Log在 /Users/eran/Library/Logs/Unity/Editor.log , eran为你的用户名)

这样的话 第一个心结就解开了, 看来Unity果真没有这么傻... 以后使用NGUI制作Atlas时候也不用担心是否需要删除小图这件事了.
既然知道了只有在真机设备上才可以进行测试,于是需要再将刚才做的测试重来一次了,只不过这次是在真机上面.
1· 首先建立一个空场景,运行,打开Profile. Texture(纹理)部分使用内存153.0KB

可以注意到,在真机上面运行时候 内存占用明显降低了,并且开销的线很平,不再像编辑环境一样会有波动.
2·加入一张图片并放置在场景上面

虽然没有像想象中的那样为1.5MB,不过 既然小于3MB,则Unity3D肯定不可能留有一份内存的备份(DRAM一份 VRAM一份,DRAM的用于处理LostConext时候重新上传GPU).
这里面其实还有一个小插曲:
在Android上面 Rendering中显示 使用的显存为0,这点和我理解的3D渲染原理不符呀,一直让我困惑了很久。后来突然想到 难道是因为手机是共享显存的原因?
果不其然 当我把项目发布为PC版本时候 再跑Profile,显存占用就有数字了. 并且显存占用数和我后面说道的动态剔除还有关系,说明显存还发生了swap,这块和所讲的事情无关
就不细说了,如果大神对这块很了解 希望指点我一下.
ok 继续说上面提到一嘴的 动态剔除,这个是我无意发现的,
我把上面那张图加了一个Animation 让其左右移动,当我真机测试时候,当这张图片移出屏幕时候DrawCall会减1,也就是只要屏幕看不到的东西Unity会自动帮你剔除,
减少DrawCall, 其实细想想, 这个是很正常的一个事情,因为Unity是一个完全的3D引擎,这也是为什么在Unity里面没有像素 进来单位是Unit,没有屏幕的宽高,只能调整摄像机的视野.
相比之下之前用的Starling,Cocos,虽然底层也在使用GPU进行渲染,但是他的整体引擎架构是基于2D的,所以自然无法在底层完成这种自动剔除以及显存交换的行为.相比之下Unity要优越许多.
就此Unity的一大谜题得以解开,根据上面的实验我得到了如下两条结论
结论: 即使项目中有许多未使用的图片,只要未放置在特殊文件夹下(Resource,StreamingAssets)并且没有被Prefab引用,最终导出时候不会被打包,更不会占用显存,但是在开发阶段会.
结论: Unity 会自行对移出场景的对象进行剔除从而减少DrawCall
Prefab 最好的管理内存(显存)的方式
我的刨根问底行为到这里并没有结束, 既然知道了Unity如何加载素材,那他什么时候卸载呢?
我又做了如下实验:
建立两个场景,SceneA,SceneB. 在SceneA中加载一张纹理,同时提供一个跳转到SceneB的按钮.
点击按钮跳转到SceneB,SceneB是一个空场景 什么都不放.
预期的是当切换到SceneB时候SceneA中所占用的显存应该会被释放,不过结果却又是让人大失所望... 仍旧没有变化
即使我在SceneB中调用GC都没用(其实看过GC介绍的朋友也应该知道在那里调GC本来就应该没用)
最后又是一通Google,不过这次没有像上次那么走运 没有任何的收获,这也是我后来转向开始研究Prefab的原因. 不过还是继续把这里说完.
又是一次意外的测试,我发现当我再建立一个SceneC时候, 由SceneA->SceneB->SceneC 这个时候 SceneA中的显存会得到释放. 就此问题我还发了一个Question.
有个朋友给了他项目上的证实,Unity确实如此 http://ask.unitymanual.com/question/36097
既然Unity自动管理的内存需要跨两个场景才能消除,那我们有没有办法自己控制呢? 方法是有的 那就是使用Prefab.
如何创建及如何使用Prefab 松雨的那两篇文章已经说的非常明白了,我就不重复造轮子了.
结论: Unity自身的显存回收是需要经过跨两个场景,如果使用Prefab在调用assetBundle.Unload (true)时候可以释放显存。
从Profile中窥探Unity的内存管理的更多相关文章
- 刨根问底U3D---从Profile中窥探Unity的内存管理
这篇文章包含哪些内容 这篇文章从Unity的Profile组件入手,来探讨一下Unity在开发环境和正式环境中的内存使用发面的一些区别, 并且给出了最好控制内存的方法(我想你已经知道了...Prefa ...
- C语言中储存类别和内存管理
C语言中储存类别和内存管理 储存类别 C语言提供了多种储存类别供我们使用,并且对应的有对应的内存管理策略,在了解C中的储存类型前,我们先了解一下与储存类型相关的一些概念. 1. 基础概念 对象:不同于 ...
- 深入了解C#系列:谈谈C#中垃圾回收与内存管理机制
今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...
- C#中垃圾回收与内存管理机制
今天抽空来讨论一下.Net的垃圾回收与内存管理机制,也算是完成上个<WCF分布式开发必备知识>系列后的一次休息吧.以前被别人面试的时候问过我GC工作原理的问题,我现在面试新人的时候偶尔也会 ...
- .net core中的高效动态内存管理方案
.net core在新增的System.Buffers中引入了一大堆高效内存管理的类,如span和memory.内存池.本文今天这里介绍一个高效动态内存访问方案. ReadOnlySequenceSe ...
- Unity资源内存管理--webstream控制
一 使用前提 1,需要使用资源热更新 2,使用Assetbundle资源热更(AssetBundle是产生webstream的元凶) 二 为什么要用AssetBundle AssetBundle本质上 ...
- Unity游戏开发中的内存管理_资料
内存是手游的硬伤——Unity游戏Mono内存管理及泄漏http://wetest.qq.com/lab/view/135.html 深入浅出再谈Unity内存泄漏http://wetest.qq.c ...
- javascript中的内存管理
目录 简介 内存生命周期 JS中的垃圾回收器 引用计数垃圾回收算法 Mark-and-sweep回收算法 调试内存问题 闭包Closures中的内存泄露 javascript中的内存管理 简介 在c语 ...
- 从内存管理原理,窥探OS内存管理机制
摘要:本文将从最简单的内存管理原理说起,带大家一起窥探OS的内存管理机制,由此熟悉底层的内存管理机制,写出高效的应用程序. 本文分享自华为云社区<探索OS的内存管理原理>,作者:元闰子 . ...
随机推荐
- Directx 3D编程实例:多个3D球的综合Directx实例
最近朋友建议我写一些关于微软云技术的博客留给学校下一届的学生们看,怕下一届的MSTC断档.于是我也觉的有这个必要.写了几篇博客之后,我觉得也有必要把这一年的学习内容放在博客做个纪念,就这样写了本篇博客 ...
- 《火球——UML大战需求分析》(第1章 大话UML)——1.2 结构型的UML(Structure Diagram)
说明: <火球——UML大战需求分析>是我撰写的一本关于需求分析及UML方面的书,我将会在CSDN上为大家分享前面几章的内容,总字数在几万以上,图片有数十张.欢迎你按文章的序号顺序阅读,谢 ...
- google(转帖)
本帖最后由 qiushui_007 于 2014-6-10 16:14 编辑 IP Addresses of Google Global Cachewww.kookle.co.nr Bulgaria ...
- Effective C++ 总结(三)
五.实现 条款26:尽可能延后变量定义式的出现时间 如果你定义了一个变量且该类型带一个构造函数或析构函数,当程序到达该变量时,你要承受构造成本,而离开作用域时,你要承受析构成本.为了减少这个成本,最 ...
- 异步编程中使用帮助类来实现Thread.Start()的示例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Gradle学习目录总结
如果是你想干的事情,在别人看起来可能是很难的一件事,不过你自己很喜欢,你不会觉得很苦.我开始创业那会是28岁.对我来讲,我创业的目的不是为了自己当老板,我希望有一个平台有一个环境,我可以控制一些资源, ...
- Java基础知识强化之集合框架笔记07:Collection集合的遍历之迭代器遍历
1. Collection的迭代器: Iterator iterator():迭代器,集合的专用遍历方式 2. 代码示例: package cn.itcast_03; import java.util ...
- 给方法传递参数:ref参数和out参数
/*--------------------------------------------------- 给方法传递参数:ref参数和out参数 (P106) ------------------- ...
- tomcat发布去掉项目的名称
1.找到tomcat的文件夹,打开conf目录的server.xml,我的是Linux系统所以用vi server.xml,总之打开就行 2.找到如下语句 加入下面箭头的路径,docBase为项目所在 ...
- GIT学习(一)-->Git产生的历史原因
首先要说:Git是目前世界上最先进的分布式版本控制系统(没有之一). git的作者:Linus,林纳斯(下图就是,先膜拜一下,因为成就可不止这一点) 他是为何要写git的呢?话说 Linus虽然创建了 ...