芊芊551 发表于 2020-12-12 18:00

Unity的坑?

我们平时总是会抱怨Unity有很多坑,但个人觉得出现这种状况的原因并不完全是Unity的坑太多。主要原因还是Unity对于大部分使用者来说是个黑盒,我们并不完全了解引擎的内部实现和调用过程,这很容易产生一些低效的用法,毕竟引擎是允许你那样去用的。
比如这个关于协程WaitForSeconds的经典问题:
IEnumerator MyMethod()
{
    //do something

    yield return new WaitForSeconds(2);

    //do something
}很显然,每一次调用都会new一个WaitForSeconds对象,产生GC Alloc;通常的优化都会是主动创建一个WaitForSeconds对象,这样就不会在每一次调用MyMethod()时产生GC Alloc了。像这样:
WaitForSeconds waitSecond = new WaitForSeconds(2);
IEnumerator MyMethod()
{
    //do something

    yield return waitSecond;

    //do something
}
OK,这没问题,是完全可行的。
然而有一次有一个客户询问如果这样优化的话,如果调用MyMethod()两次,第二次调用在第一次调用一秒钟之后,那么第二次调用会等待多久呢?这本质上是在问yield return 的对象有没有被Unity native层所引用;
如果有被引用的话,那第二次调用应该只会等待一秒
如果没有被引用的话,那不管调用时机是怎么样的MyMethod()都会等待2秒钟

根据使用经验或者测试,我们能猜到可能是第二种情况,也就是没有被引用。好,这个问题先放放,我们先来看另一个问题:
private IEnumerator MyLoad(string path)
{
    WWW www = new WWW(path);
    yield return www;

    if (www.isDone)
    {
      // do something
    }
}
问题来了,这里的www对象会被native层引用吗?
显然是会的,不然www.isDone是谁修改的?这么看来yield return的对象是否被引用并不能一概而论。
事实上WaitForSeconds对象确实并没有被引用,它在native层做了特殊处理,可以把它看成是向coroutine发送的一个消息,而native层针对WaitForSeconds消息生成了一个内部结构并保存在列表里。
因此,WaitForSeconds的写法都基于我们是否足够了解Unity的内部细节,而它所谓的优化在了解内部细节的情况下是一种很自然的写法。要回避掉这种坑需要我们对Unity内部有更好的理解。以后我将会不时为大家带来一些内部剖析,希望可以使大家更好的使用Unity。
页: [1]
查看完整版本: Unity的坑?