最近,在国服上的新职业技能,包含了一个弱点标记技能。玩家用技能打怪的时候,有一定概率给怪挂上弱点,下次攻击时用另一个技能攻击弱点,能爆出更大伤害。弱点的生命周期大约半分钟,过了以后弱点会消失,玩家退出场景后,弱点也会消失。

实现的时候,弱点命中情况记在了受害者身上,同时注册监听了一个玩家死亡事件,方便玩家死亡的时候,清理受害者身上记录的玩家命中弱点信息。但是实现的时候,漏掉了反注册监听事件,导致怪物虽然死亡,但是事件管理器上还一直引用着这个对象,引发内存泄漏。

万幸的是,对于场景服务,之前加上了 skynet.memlimit 的 2G 内存限制。同时,因为同一个场景有多个分线,玩家没法进去的时候,会自己切换到另一个分线继续,所以没酿成重大事故。内存满了的服务,不会再接受 call 请求,所以玩家继续 call 的话,会变成玩家上的 task 堆积

这个问题修了两次才修好,需要引以为戒。第一次修的时候,换了一套事件管理器,以为新的管理器会自动在怪物死亡时,清理它监听的事件。同时,看日志的时候只看到 gc 后内存小了,没有具体打印出怪物的数量来排查,测试的时间也比较短,需要一段时间才能看出来漏没漏的。。第二次添加了反注册监听事件就好了

还有值得改进的,是以后开发这种复杂对象相互引用的,还是能用 id 就用 id,避免错误引用住复杂对象。同时,事件管理器也可以优化一下,a 对象关心 b 对象的事件,当 a 或者 b 死亡的时候,就应该清理注册的 a 关心 b 的事件,避免手残引起内存泄漏。。