Unity内存优化

1.代码层面


1.foreach
Mono下的foreach使用需谨慎,频繁调用容易触及堆上限,导致GC过早触发,出现卡顿现象。
特别注意的是在Update中如果非必要,不要使用foreach。尽量可能用for代替foreach.会产生GC Alloc,说明foreach调用GetEnumerator()时候会有堆内存上的操作,new 和dispose。
2.string
如果熟悉C++的话,就会了解,每次使用string的时候,都要在内存中创建一个新的字符串对象,就需要为该对象分配新的空间。特别是在循环中修改string对象,就会频繁地分配空间,这个时候推荐使用StringBuilder.Append等操作来处理。C++中通常也是通过分配一个固定的字符内存来处理字符串操作。
3.string
gameObject.tag会在内部循环调用对象分配的标签属性以及拷贝额外的内城,推荐使用gameObject.CompareTag("XXX")来代替.tag
4.ObjectPool
使用ObjectPool管理对象,避免重复的Instance,Destroy。

2.贴图层面


1.通过调整纹理资源,来调整图的大小。比如:九宫格

2.IOS平台使用PVRT压缩纹理,Android使用ETC1格式压缩。但是ETC1不支持Alpha通道的图片压缩。所有一般把Alpha通道图分离出来,绘制到GPU显存时,a值从Alpha图获取,无Alpha通道的图就是用ETC1压缩。
ETC2支持Alpha但是适用机型太少了。

3.minMap 离摄像机远近不同用不同的图片。

4.通过减色的方式减少图片大小。许多UI其实用的色彩很少,用不到256色。这类图片就可以使用减色压缩。

3.架构设计


1.峰值要求:
Android平台:在客户端最低配置以上,均需满足一下内存消耗指标(PSS):
a)内存1G以下机型:最高PSS<=150MB
b)内存2G机型:最高PSS<=200MB
IOS平台:在iPhone4S下运行,消耗内城(real mem)不大于150MB。

2.场景切换时避开峰值
当前一个场景还未释放的时候,切换到新场景。这时候由于两个内存叠加很容易达到内存峰值。解决方案是,在屏幕中间遮盖一个Loading场景。在旧的释放完,并且新的初始化结束后,隐藏Loading场景,使之有效的避开内存大量叠加超过峰值。

3.GUI模块加入生命周期管理
主角、强化、技能、商城、进化、背包、任务等等。通常一个游戏都少不了这些系统。但是要全部都打开,或者这个时候再点世界地图,外加一些逻辑数据内存的占用等待。你会发现,内存也很快达到峰值。
这时候有效的管理系统模块声明周期就非常有必要。首先将模块进行划分:
a)经常打开Cache_10;
b)偶尔打开Cache_5;
c)只打开一次Cache_0;

创建一个ModuleManager类,内部Render方法每分钟轮回询问一次。如果是"Cache_0"这个类型,一关闭就直接Destroy释放内存,如果式“Cache_5"这个类型就5分钟释放。Cache_10就10分钟。每次重新打开就重新计时。

4.资源方面


1.资源类型
GameObject,Transform,Mesh,Texture,Material,Shader,noxss和其他Assets。

2.资源创建方式
  • 静态引用,在脚本中加一个public GameObject变量,在Inspector面板 拖一个prefab到该变量。
  • Resource.Load,资源需要放在Assets/Resources目录。
  • AssetBundle.Load,通过AB加载。

3.资源销毁方式
  • Destroy(GameObject).直接销毁物体释放内存。
  • AssetBundle.Unload(false),释放AssetBundle文件内存镜像,不销毁Load创建的Asset对象。
  • AssetBundle.Unload(true),释放AssetBundle文件内存镜像同时销毁已经Load创建的Asset对象。
  • Resources.UnloadAsset(Object),释放已经加载的Asset对象。
  • Resources.UnloadUnuserdAssets,释放没有引用的Asset对象。

4.生命周期
a.Resources.Load(同静态引用)
Resources.Load一个Prefab相对于Instantiate一个资源来说是一个相对轻量级的操作。上述过程中,Resources.Load加载一个Prefab几乎没有消耗内存,而Instantiate消耗了2.5M的资源空间。Resouces.Load增加了Mesh和TotalObject的数量,而Instantiate增加了GameObjects,Objects In Scene和Total Objects。
Destroy一个GameObject之后,内存有所减少,但是比较少。Instantiate和Destroy前后Material和Texture没有还原,供以后Instantiate继续使用。所以需要调用Resurces.UnloadUnusedAssets。

b.AssetBundle.Load
通过WWW Load AssetBundle 的方式加载一个资源会自动加载相应的Mesh,Texture和Material,而通过Resources.Load方式进行加在只会加载Mesh信息,因此通过AssetBundle方式加载后,Instantiate一个资源的内存消耗比较小。
总结:
使用Resources.Load的时候在第一次Instantiate之前,相应的Asset对象还没有创建,直到第一次Instantiate的时候才会真正的取读取文件创建这些Assets。它的目的是实现一种OnDemand的使用方式,到该资源真正使用的时候才会去创建这些资源。

而是用AssetBundle.Load会直接将资源文件读取出来创建这些Assets,所以第一次Instantiate的代价相对比较小。

而Instantiate的过程是一个对Assets进行Clone(复制)和引用相结合的过程。Clone的过程需要申请内存存放自己的数据,而引用的过程只需要直接一个简单的指针指向一个已经Load的资源即可。例如Transform是通过Clone的。而Texture和TerrainData是通过引用复制的。而Mesh,Material,PhysicalMaterial和noxss是两者皆有的。
Destroy只会销毁Clone出来的Assets并不会销毁引用的。因为Destroy并不知道是否有其他人还在引用这些东西。所以需要使用Resurces.UnloadUnusedAssets
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值