由UnityEngine.Object该怎么判空引发的一些思考

1.测试数据分析

  先给出一组测试数据,分别用三种比较方式进行100万次UnityEngine.Object的判空。

比较方式耗时(毫秒)
obj == null43
obj is null4
System.Object.ReferenceEquals(obj, null)4

  一开始的时候用GameObject和继承MonoBehaviour组件拿到的测试结果不一样,GameObject用ReferenceEquals或者 is null比较速度只能提升一倍,后来发现是忘记缓存gameObject了(在MonoBehaviour脚本里直接写的gameobject是一个属性,虽然一般不会造成性能问题,但在测试时不加注意可能会得到错误的结论)。
  拿到这个数据后就可以开始猜测了,is null就是一个语法糖,通过上述数据可以猜测is null 会被翻译成ReferenceEquals。那么ReferenceEquals为什么会快这么多呢。

2.ReferenceEquals

  既然ReferenceEquals要快这么多,那就去看一下实现,不看不要紧,一看吓一跳,这不就是 == 么。一开始还怀疑是不是上面加的两个特性捣的鬼,查了一下排除了。

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[System.Runtime.Versioning.NonVersionable]
public static bool ReferenceEquals (Object objA, Object objB) {
    return objA == objB;
}

  那么会不会是函数参数是system.object造成的呢,于是增加两种比较方式得到以下结果

比较方式耗时(毫秒)
obj == null43
obj is null4
(object)obj == (object)null4
SelfEquals(obj, null)9

SelfEquals实现如下

bool SelfEquals(object obj1, object obj2)
{
    return obj1 == obj2;
}

  到这里事情就有点意思了,到这时可以暂时理解为把UnityEngine.Object转成System.Object比较会快一些。自己写SelfEquals慢一点估计是因为多了一层函数调用。

  最后用ILSpy反编译一下unity生成的dll,发现直接使用==时,编译器翻译的最终c#代码是这样的

if ((Object)(object)obj == (Object)null){}

  而其它几种都是这样的

if (obj == null){}

  如果比较的不是UnityEngine.Object,而是继承自System.Object的类的话则最终翻译到的c#代码都是第二种情况。

3.总结

  unity有三大内存域,跨域的通信过渡会造成性能上的损失,由于UnityEngine.Object的数据是保存在本地域上,直接使用 == 时可能会引发本地域和托管域之间的桥梁通信过度,从而造成速度变慢。而把他们当作System.Object做比较时,应该是只在托管域中做了一次引用比较。

  • 本地域
  • 托管域
  • 外部dll
  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值