unity内存减少方法集合

来源:互联网 发布:周小平什么学历 知乎 编辑:程序博客网 时间:2024/06/03 15:46

本文集合了网上许多关于U3D内存减少方法的说发。以及自己总结的方法;


图片类:

(1)纹理格式选择

下图中 format 选项:Android平台选ETC、iOS平台选PVRTC、Windows PC上选DXT等等

ETC1 不支持透明通道---RGB格式
ETC2 支持透明通道-----是RGBA的格式
ETC后面都有个bit,bit越小图片质量越差,bit就根据情况来选择了
这两种都是安卓平台的图片格式,具体选择哪种要根据情况来选择。ios平台暂时没研究。


(2) Mipmap功能要关闭

Mipmap旨在有效降低渲染带宽的压力,提升游戏的渲染效率。但是,开启Mipmap会将纹理内存提升1.33倍。对于具有较大纵深感的3D游戏来说,3D场景模型和角色我们一般是建议开启Mipmap功能的,但是经常会发现部分UI纹理也开启了Mipmap功能。这其实就没有必要的,绝大多数UI均是渲染在屏幕最上层,开启Mipmap并不会提升渲染效率,反倒会增加无谓的内存占用。

(3) Read & Write
纹理资源的“Read & Write”功能在Unity引擎中是默认关闭的。开启该选项将会使纹理内存增大一倍。
Texture2D有个readwrite enable属性,这个属性的实质是决定了这个贴图的存放位置,是在内存上还是在显存上。(虽说在移动设备上显存和内存是共用的,但数据不直接互通) 如果可读写,那么这个贴图既在显存上,又在内存上,而且还必须得是非压缩的格式(ARGB32,ARGB4444之类)。用getPixel(s),setPixel(s)之类的方法,读取或设置的数据,都是内存上的数据,但其他属性不区分内存还是显存。Apply方法的作用是把这个贴图在内存上的传给显存。Apply方法的第二个参数,决定了这个这个贴图是否还可读写,换种说法就是内存上这部分数据在执行完这个方法之后还要不要
(关于图片的属性NON POWER OF 2等请看链接 http://blog.csdn.net/alayeshi/article/details/52958393)

代码方法减少内存:

1.引擎在执行UnloadUnusedAssets操作(该操作是比较耗时的,建议在切场景的时候进行).


2.尽可能地避免使用Unity内建GUI,避免GUI.Repaint过渡GC Allow.


3.if(other.tag == GearParent.MogoPlayerTag)改为other.CompareTag(GearParent.MogoPlayerTag).因为other.tag为产生180B的GC Allow.


F. 少用foreach,因为每次foreach为产生一个enumerator(约16B的内存分配),尽量改为for.


G. Lambda表达式,使用不当会产生内存泄漏.


H. 尽量少用LINQ:


1.部分功能无法在某些平台使用.


2.会分配大量GC Allow.


I. 控制StartCoroutine的次数:

1.开启一个Coroutine(协程),至少分配37B的内存.

2.Coroutine类的实例 — 21B.

3.Enumerator — 16B.


J. 使用StringBuilder替代字符串直接连接.

在Update方法或循环中,少用string类,因为string类的每次操作都会调用new生成新字符串对象。用StringBuilder代替string,StringBuilder基于固定Buffer操作,从而避免了内存的分配。


K. 缓存组件:

1.每次GetComponent均会分配一定的GC Allow.

2.每次Object.name都会分配39B的堆内存.




总结一下各种加载和初始化的用法:


AssetBundle.CreateFrom.....:创建一个AssetBundle内存镜像,注意同一个assetBundle文件在没有Unload之前不能再次被使用
WWW.AssetBundle:同上,当然要先new一个再 yield return 然后才能使用

AssetBundle.Load(name): 从AssetBundle读取一个指定名称的Asset并生成Asset内存对象,如果多次Load同名对象,除第一次外都只会返回已经生成的Asset 对象,也就是说多次Load一个Asset并不会生成多个副本(singleton)。


Resources.Load(path&name):同上,只是从默认的位置加载。
Instantiate(object):Clone 一个object的完整结构,包括其所有Component和子物体(详见官方文档),浅Copy,并不复制所有引用类型。有个特别用法,虽然很少这样 用,其实可以用Instantiate来完整的拷贝一个引用类型的Asset,比如Texture等,要拷贝的Texture必须类型设置为 Read/Write able。


总结一下各种释放


Destroy: 主要用于销毁克隆对象,也可以用于场景内的静态物体,不会自动释放该对象的所有引用。虽然也可以用于Asset,但是概念不一样要小心,如果用于销毁从文 件加载的Asset对象会销毁相应的资源文件!但是如果销毁的Asset是Copy的或者用脚本动态生成的,只会销毁内存对象。


AssetBundle.Unload(false):释放AssetBundle文件内存镜像
AssetBundle.Unload(true):释放AssetBundle文件内存镜像同时销毁所有已经Load的Assets内存对象
Reources.UnloadAsset(Object):显式的释放已加载的Asset对象,只能卸载磁盘文件加载的Asset对象
Resources.UnloadUnusedAssets:用于释放所有没有引用的Asset对象
GC.Collect()强制垃圾收集器立即释放内存 Unity的GC功能不算好,没把握的时候就强制调用一下

在3.5.2之前好像Unity不能显式的释放Asset


销毁时:
对Instantiate的对象进行Destroy
在合适的地方调用Resources.UnloadUnusedAssets,释放已经没有引用的Asset.
如果需要立即释放加上GC.Collect()
这样可以保证内存始终被及时释放
只要你Unload过的AssetBundle,那些创建的对象和引用都会在LoadLevel时被自动释放


0 0
原创粉丝点击