5. 培养敏锐的异常反应
我们经常在老程序口中听到对称、平衡、泄漏等词汇,如果不注意就容易出现内存泄漏或者其他问题。对称,指的是类似于创建对应销毁,申请对应释放。在C/C++开发的程序中经常会被提到要做好内存的申请与释放。在unity引擎开发的程序中,会被提到要注意资源的使用与释放。关注对称是值得我们培养的意识。那么,不对称意味着什么?
我们先来看一段底层框架日志的输出
-----------------------
OnCreateWindow Test1
OnCreateWindow Test2
OnDestroyWindow Test2
这个日志输出简单的解释可以理解为先创建了Test1窗口,紧接着创建了Test2窗口,随后销毁了Test2窗口。
那么假设对应的界面为下面的情况:
1. 只在界面上看到过Test1
这意味着Test2 是在同一帧进行创建和销毁
2. 界面上出现Test1,接着出现Test2,随后关闭了Test2,关闭了Test1这意味着底层框架出现了问题,底层框架并没有办法在任何情况都做到在窗口关闭的时候捕获销毁事件
我们再看下另外一种日志:
-----------------------
OnCreateWindow Test1
OnCreateWindow Test1
OnDestroyWindow Test1
这个日志输出简单的解释可以理解为 先创建了Test1窗口,紧接着再次尝试创建了Test1窗口,随后销毁了Test1窗口。
那么假设对应的界面为下面的情况:
1. 在界面上看到过Test1,点击了一次后Test1被销毁了
这意味着底层防止了创建相同的窗口
2. Test1创建,并没有被销毁
这意味着底层可能使用引用计数管理界面,只有界面引用计数为0的时候才销毁窗口
3. 在界面上看到过Test1,点击了一次关闭后Test1还在
这意味着底层允许创建同类型的窗口,并且区别对待每个实例
我们尝试把一个生命周期里面(对应上面就是在界面上看到窗口创建和销毁的过程),出现的AAB型日志或者其他AB数量不平衡的日志称为不对称日志。这种日志都代表了异常或者发生了bug。当然,我们这么说的前提是我们的设计不能以容错来设计,参考断言与返回这一节。那么在这种非容错的设计下面:
------------------------------
OnCreateWindow Test1
OnCreateWindow Test2
OnDestroyWindow Test2
OnDestroyWindow Test1
上面的输出意味着干净的资源管理
------------------------------
OnCreateWindow Test1
OnCreateWindow Test1
OnDestroyWindow Test1
OnDestroyWindow Test1
上面的输出可能意味着底层使用了引用计数进行管理
------------------------------
OnCreateWindow Test1
OnCreateWindow Test2
OnDestroyWindow Test2
OnDestroyWindow Test1
上面的输出可能意味着底层使用栈的方式管理窗口, 先进后出。
无论怎么样,在对称的艺术下,我们就可以去更多的关注设计层面。我们来看一个例子。
在某个凌晨的夜晚,睡在梦中的老A被某个电话叫醒。他收到来自小B的一个截图。截图上面只有一小段,
OnGateConnect 1 0
OnGateConnect 2 1
OnGateDiscconnect 2
OnWorldDiscconnect
表现的现象是无法参与跨服玩法了。根据经验,已经可以猜测OnWorldDiscconnect就是导致跨服无法参与的原因。那么导致这个跨服失败的情况可能是什么?小B的分析是即使上面出现了AAB型日志,但是因为它不是一个完整的生命周期(进程启动到结束是一个生命周期,这时候进程还在运行,生命周期并没有结束),所以这个输出不能得出什么有效信息。老A在床上看着这个输出,陷入了思考。
是的,这不是个完整的生命周期,所以是会出现AAB型的日志的。但是假如OnGateConnect 1是正常的连接并且没有触发OnGateDiscconnect,为什么会出现OnGateConnect 2 与OnGateDiscconnect2的对称,部分对称部分不对称是不合理的。依据这个不合理,老A最终得出了OnGateConnect 2从出现就是不合理的结论,避免了一次通宵。
所以,在非生命周期中,对称也可能变成一种异常。而在生命周期内,非对称往往是一种异常。这种非生命周期对称异常和生命周期非对称异常都值得我们关注。