===》这是一遍尴尬的日志。。因为一开始就是错误的。。所以结局也是错误的。。
GetComponent这个接口在PC上消耗惊人,但是在手机上消耗非常少,大概24Byte。。
1、首先要说一下GetComponent这个接口的GC消耗
下图中的Other里只做了一件事情:m_Mask=GetComponent();
可以看出,一次调用产生0.6KB的GC,这是我们的背包界面,有200多张Image,光一个Awake产生116KB的GC。
2、UGUI的Image、Text都继承自MaskableGraphic
下图可以看到一堆OnEnable的消耗点开看详细列表,和图一是多么的相似~
然后看源码:
每个Text和Image在显示的时候,都要走一遍这个OnEnable,一次0.5~0.6KB,几乎每个项目里用到这两个控件的地方是成百上千,前面图中的GC如果扣掉这部分的消耗,就是很少很少很少~
OnDisable也是一样的道理,直接看图:
所以为什么UI对象SetActive DeActive会产生那么多的GC,大家想尽歪门邪道去解决这个问题,比如关闭界面把UI挂到其他非canvas节点,移出视野(这种办法有很大概率触发子线程的sorting或者batch异常导致crash)。
我们项目现在使用的办法是给所有UI界面挂一个canvas,需要关闭窗口的时候disable这个canvas,canvas下的粒子系统加一个UIBehavior脚本监听这个canvas是否隐藏去做特殊处理(关闭界面的时候stop这个particlesystem,打开界面的时候play);对于canvas下挂了resorting的子canvas,只能用原来的方式继续用SetActive啦
3、让我们看看哪些UI继承了MaskableGraphic
4、还有另外一个坑,这个接口也是高频率调用,OnEnable和OnDisable的时候会调用,看起来UI发生网格重建的时候也会调用,这个问题我们一开始处理的方式比较粗暴,就是直接将它移到Awake,这样对象生命周期内只发生一次调用,就是图一中看到的现象。但是这样也是不好的,这样就意味着游戏里打开的所有Image、Text都要经历一遍这个GetComponent的洗礼,还是一句话,偶尔几个地方可以忍了,但是所有节目加起来大概有几千个这个控件吧。。
所以最终,我们的解决方案是,(我们游戏里的所有Image、Text是用我们自己改写过的版本,继承了原生的Image和Text),在SDImage和SDText里加一个Mask成员变量,在编辑器模式下设置好这个值……
5、其实有更好的办法
重写MaskableGraphic,重写那几个继承自MaskableGraphic的对象,自己定制一组UI,其实Image和Text就基本够用了。这样前面我说的旁门左道都可以不需要,还可以愉快的Active和DeActive。下个版本我们打算这么干!!