unity内存管理

一、内存管理
1:GC原理
   C#的垃圾回收是自动托管的,垃圾回收系统也有一套生命周期和统计流程,下面就是关于GC的整体流程:
    1)一次GC的过程分为2个阶段:
    标记清除阶段,GC会假设堆中所有对象都可以被回收,然后找出不能回收的对象,打上清除标记,剩下的就是要被回收的了。找的过程就是检查对象 有没有被其他的对象引用的过程,如果这个对象在程序中没有被引用到,那么就会被打上清除的标记。
    重新地址排列阶段,标记清除的对象被清除之后,堆里面的空间就会变成不是连续的了,GC的第二部就会开始重新排列还存在的对象,使堆中的地址 分配变成连续的。
    2)整个.net的GC流程:
   在进行.Net的GC阶段,是不止一次GC操作的,C#采用了分代算法,先对程序里面的内存进行分代管理,再根据不同的代,进行不同力度的清理。
  
这里面的生命周期为3代, 第0代是新创建的代码,在达到了0代集合的阈值之后,触发0代的GC,幸存的对象会进入1代集合, 同理,在1代集合达到了阈值 的时候,也会进行GC,但是这次GC是 0代和1代一起执行,以此类推,2代集合GC的时候也会进行1代 2代的CG操作。按消耗量的比例应该是 1:10:100

这种分代算法是基于 老的对象生命周期一般都比新的对象生命周期长,就像公司的员工一样,时间较长的员工公司看来一般都比新进来的员工稳定性要大。

2:优化策略

明白了大致GC的流程之后会发现,GC会消耗大量的CPU性能,因为这里面会经历很多次的运算以及遍历等

接下来是弄清楚GC什么时候被触发,以及如何规避影响用户体验的GC操作

何时会触发GC?
    三种情况下会触发GC:
    1:跟进分代算法,在容量达到阈值的时候会发生,
    2:GC会不时的自动运行(频率因平台而异)。
    3:手动强制调用GC

大致的优化思路就是 降低每一次GC的运行时间(减少垃圾对象,使GC的过程中尽量少的遍历),降低GC的频率(降低触发GC机制的次数),在加载地图等需要用户等待的游戏流程里面主动GC。

接下来就是跟进3种触发机制做我们代码上的优化了

1)、尽量少new不必要的字段

 1 object obj = null;
 2 update()
 3 {
 4      object = somebody;
 5 }
 6 
 7 update()
 8 {
 9     object obj =somebody;
10 }

上面的赋值方式只会在开辟一个内存空间,第二种会反复开辟内存空间,这些空间一般在一代GC里面就会被释放掉。属于最无用的代码方式(没必要的 情况下)。

2).使用对象池
    对象池的使用会大大降低新内存空间的使用,他会在一个内存空间反复给新的值。
3).尽量使用缓存机制,少使用Instantiate实例化新对象,因为这里Unity会初始化他身上的组件以及各种序列化的操作,各个物体会根据自身的组件,创建耗时都 不相同
4).字符串的操作
string的拼接操作是在内部重新new 一个新的出来,因为string在C#是不可变更到,所以在每一次的+= 就相当于new了一个新的字符串出来,如果出现比较频繁 的拼接操作,stringBuilder会比string 更好,但是string在对字符串的操作上会比stringBuider好,至于使用哪一种就看具体的需求了。
5).在地图加载等需要等待的过程中主动进行GC。
避免内存消耗还有很多的方式,我也是刚刚开始比较全面的学习性能优化,在以上也是我在网上搜集了一些自己能理解的处理方式。

CPU性能管理:

一、代码层:
  1、 尽量避免空的Update(),只要写了Update(),不管是不是空的,Unity都会去执行,这里会增加开销
  2、Find getcomponent 等查找的方法,Unity都会去遍历场景对象和组件,在大型项目中,场景对象一旦变多就会产生很大的开销了,尽量在start里面调用而不 是update里面反复使用
3、Update里面尽量少做遍历,一次UpDate 就会遍历一次,这是一个很大的开销了。
4、在业务需求不影响的情况下,可以让Update里面的逻辑使用计时器,增加间隔,1秒调用一次,2秒调用一次等。
5、在可以知道触发条件的情况下,尽量使用委托的方式处理触发效果,而不是一次次的遍历目标的触发状态
6、和上面一样,尽量在设计代码的时候,使用观察者模式,理论上来说,游戏的大部分逻辑都可以使用触发后再执行,特别是UI。(在使用lua热更新的项目 中,大部分的游戏逻辑流程都是通过事件消息的触发来完成的,因为里面没有Uinty那么专业的生命周期)
7、for 和 foreach 的取舍 :
    在固定长度或长度不需要计算的时候for循环效率高于foreach.
    在不确定长度,或计算长度有性能损耗的时候,用foreach比较方便
二、渲染层:

  	渲染层的优化包括 图集的结构设计、模型的处理、LOD、mipMap、烘焙等、阴影处理
  	
    图集的结构设计是为了减少额外的draw call,尽量以模块划分,因为原则上每个模块之间的UI元素是不会互相耦合的。Unity的texture的大小是根据2的幂来计算到。如果你的图片真实大小是1025,那么他会创建一块2048的texture,也是浪费开销的行为。
    
	模型的处理要结合LOD的使用,在固定视角、固定摄像机深度的游戏中,LOD的发挥效果不是很大,更多的是制作模型的时候就确定了模型精度
	
 	LOD和MipMap的使用会带来很大的性能提升,但是会受项目影响,具体看项目而定

	烘焙就是在游戏发布之前,场景融合光照提前产生新的贴图,使这个场景不用进行动态光照计算 就可以达到光照的效果,降低了CPU计算的开销,但是对用户的体验肯定没有实时光照那么好,一般都是出现在手游中

	阴影和烘焙的道理差不多,为了降低实时光照的计算量,可以将阴影设置为假阴影,阴影在是圆的情况,不会产生旋转的变化,同时因为烘焙的原因,光线没有入射角的变化,也不会产生阴影的投射角度变化,也是在优化性能上比较常用的方式

转自
https://www.cnblogs.com/leixuan111/p/10737143.html

非常详细的说了profile的使用和存在与cpu或者gpu的分析,满满的干货
https://www.jianshu.com/p/a7cee5e548cf

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值