标题可能有点强,但让我解释一下我是如何理解会发生什么的。我猜这发生在Tomcat上(引用的消息来自Tomcat),但我不确定了。
TL; DR在底部有一个总结,为什么我声称这是Web服务器的错误。
我可能错了(但没有错误的可能性,没有理由问):
ThreadLocal
ThreadLocal
引用库中的对象ClassLoader
网络服务器
如果我理解正确,在重新部署之后,旧的“脏”线程将继续被重用。他们的ThreadLocal
引用引用其ClassLoader
引用整个旧类层次结构的旧类。所以很多东西都留在PermGen
空间,随着时间的推移会导致OutOfMemoryError
。 到目前为止这是对的吗?
我假设有两件事:
因此,每次重新部署时完整的线程池更新每小时花费几分之一毫秒,即0.0001 * 12/3600 * 100%
的时间开销,即0.000033%
。
但不是接受这个微小的开销,而是countless problems。 我的计算错了还是我忽略了什么?
作为警告我们收到消息
Web应用程序...使用类型为...的键创建了一个ThreadLocal,类型为...但在Web应用程序停止时无法将其删除。
应该更好地说明
Web服务器...使用线程池但在停止(或重新部署)应用程序后无法续订。
或者我错了?即使所有线程不时重新创建,时间开销也可以忽略不计。但是在将ThreadLocal
提供给应用程序之前清除它们就足够了,甚至更快。
存在一些实际问题(最近this one),用户无能为力。图书馆作家有时可以而且有时不能。恕我直言,网络服务器可以很容易地解决它。事情发生并且有原因。因此,我责怪唯一一个可以对此采取任何行动的政党。
这个问题的标题比正确的更具挑衅性,但它有其重要意义。 raphw的答案也是如此。这个linked question还有另一个开放的赏金。
我认为网络服务器可以解决它如下:
LastCleanupTimestamp
中存储ThreadLocal
(对于新线程,它是创建时间)delta
,例如1小时)ThreadLocal
并设置新的LastCleanupTimestamp
这可以确保没有这样的泄漏存在的时间超过delta
加上最长请求的持续时间加上线程周转时间。费用如下:
ThreadLocal
(即几纳秒)ThreadLocal
(即,每个线程每delta
一次更多纳秒)DateFormat
实例。如果最近没有取消部署或重新部署应用程序,只需设置thresold就可以关闭它。