PowerNukkitX icon indicating copy to clipboard operation
PowerNukkitX copied to clipboard

解决线程泄漏,真正实现优雅停机

Open johnbanq opened this issue 2 years ago • 0 comments

现有问题

在当前版本里,服务器是通过在main线程里执行System.exit(0)强行终止整个进程来实现停止的。

我猜想这里之所以需要强行杀掉进程,是因为Nukkit内部存在线程泄漏问题,这只是解决这个问题无可奈何的做法。但是这么做一方面不优雅(所有线程会被立刻终止,包括那些可能在执行最后一点清理逻辑的线程),另一方面会对热重启等特性的实现造成影响。

所以,我提议我们正面解决这个问题,通过好好地把尚未关闭的线程池关闭来自然地停机。

修改计划

  • [ ] 关闭线程池,实现优雅停机
    • [*] 分析main线程结束后进程无法退出的原因,揪出那些尚未被关闭的线程池
      • 目前已知的泄露有下述三个,在全部关闭后服务器是可以正常退出的:
        • PGZIPOutputStream内部的静态线程池
        • BlockStateRegistry里的asyncStateRemover
        • Metrics里的scheduler
    • [ ] 设计逻辑关闭这些线程池
  • [ ] 避免线程泄露问题复发,对可能的复发提供预案
    • [ ] 审计代码库,给所有线程池产生的线程加上对应的名字,方便检查是哪个线程池在泄露
    • [ ] 让ServerKiller在杀掉进程前列出所有线程,以便未来检查新的泄露问题
  • [ ] 收尾,删除System.exit(0)

预期好处与风险

好处:

  • 可以让所有线程正常地结束工作,比杀进程更加安全
  • 让一些方便开发者的特性,例如热重启可以被实现(不然泄露的线程会一直在内存里呆着,对热重启造成影响)

风险:

  • 一旦有新的线程泄露问题(无论是来自服务器自身还是插件),服务器的停止时间会被延长(ServerKiller需要~8秒才会杀掉进程)

johnbanq avatar Mar 29 '22 20:03 johnbanq