为什么有些网络服务器会抱怨他们创建的内存泄漏?

时间:2013-10-30 19:43:04

标签: java tomcat memory-leaks webserver thread-local

标题可能有点强,但让我解释一下我是如何理解会发生什么的。我猜这发生在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),用户无能为力。图书馆作家有时可以而且有时不能。恕我直言,网络服务器可以很容易地解决它。事情发生并且有原因。因此,我责怪唯一一个可以对此采取任何行动的政党。

关于Web服务器应该做什么的提案

这个问题的标题比正确的更具挑衅性,但它有其重要意义。 raphw的答案也是如此。这个linked question还有另一个开放的赏金。

我认为网络服务器可以解决它如下:

  • 确保每个线程在某个时候被重用(或杀死)
  • LastCleanupTimestamp中存储ThreadLocal(对于新线程,它是创建时间)
  • 重新使用线程时,检查清理时间戳是否低于某个阈值(例如,现在减去某些delta,例如1小时)
  • 如果是,请清除所有ThreadLocal并设置新的LastCleanupTimestamp

这可以确保没有这样的泄漏存在的时间超过delta加上最长请求的持续时间加上线程周转时间。费用如下:

  • 每次请求检查一个ThreadLocal(即几纳秒)
  • 反射性地清除所有ThreadLocal(即,每个线程每delta一次更多纳秒)
  • 删除可能对存储它们的应用程序有用的数据的成本。这不会破坏应用程序,因为没有应用程序可以假设查看包含它已设置的线程本地的线程(因为它甚至不能假设再看到线程本身),但它可能需要花费时间来重新创建数据(例如,如果某人仍然使用这样一个可怕的东西,则为缓存的DateFormat实例。

如果最近没有取消部署或重新部署应用程序,只需设置thresold就可以关闭它。

0 个答案:

没有答案