【问题标题】:Library Using ThreadLocal Potentially Causing Memory Leaks in Tomcat使用 ThreadLocal 的库可能会导致 Tomcat 中的内存泄漏
【发布时间】:2015-11-28 08:06:25
【问题描述】:

我正在使用 Box.com Java SDK,该库执行以下 ThreadLocal:

private static final ThreadLocal<DateFormat> THREAD_LOCAL_DATE_FORMAT =
        new ThreadLocal<DateFormat>() {
    @Override
    protected DateFormat initialValue() {
        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
    }
};

但是,我认为这是我的 tomcat 连接池问题的原因。特别是因为据报道后续泄漏会影响 HibernatePersistenceContextInterceptor。

严重:Web 应用程序 [] 创建了一个 ThreadLocal,其键类型为 [com.box.sdk.BoxDateFormat$1](值 [com.box.sdk.BoxDateFormat$1@275ab696]),值类型为 [java.文本.简单 DateFormat](值 [java.text.SimpleDateFormat@faabb360])但在 Web 应用程序停止时未能将其删除。线程将随着时间的推移而更新,以尽量避免专业人士 bable 内存泄漏。

在不重写大部分库的情况下,有没有办法处理这种情况?

【问题讨论】:

  • JDK 的哪个版本?我认为这不再是问题,因为键现在被弱引用了。
  • 很遗憾,我无法更新到 Java 8。由于框架限制,我正在使用 Java 7。

标签: java tomcat grails memory-leaks


【解决方案1】:

消息告诉您Tomcat 将替换线程以清除这些孤立的ThreadLocal 值。因此,虽然不能保证可以防止问题,但 Tomcat 正在尝试减轻错误的影响。

一般来说,这可能是个问题,因为当弱引用的ThreadLocal 实例被垃圾回收时,线程映射中的条目可能会保留一段时间,从而防止值、它的类和它的类加载器成为垃圾集。但是,由于本例中的值 (DateFormat) 来自引导加载程序,因此无论如何都不会卸载它,也不应该成为问题。

要在应用程序关闭时清除这些孤儿,您必须通过反射深入了解Thread 的内部。听起来很乱!

我会首先寻找更有力的证据来将此归咎于您的连接池问题。例如,您的连接池中是否存在因 Tomcat 替换请求线程而暴露的错误?也许这个错误更容易自己修复。

【讨论】:

  • 作为一个兴趣点,在我的简单基准测试中,看起来构建有问题的SimpleDateFormat 比实际解析日期要快。在我的工作站上,构建大约需要 1.6 ns,而解析需要 2.2 ns。因此,除非您的应用程序全部都在解析日期,否则可能不值得缓存解析器。
  • 我已经尝试解决连接池问题数周(甚至数月)。我知道它只是在我更新到休眠 4 时才开始发生。
  • @JohnGiotta 如果您可以可靠地重现该问题,请使用您已修补的 Box API 版本运行测试以完全删除 ThreadLocal,每次创建一个新的 SimpleDateFormat @ 987654328@ 或 format() 被调用。如果这样可以解决问题,那么您有一些很好的证据可以建议您接受您的补丁。如果没有,你就会知道你需要继续寻找。当您谈论微秒时,多花 75% 的时间可能没什么大不了的。
  • 抱歉,上面的数字是微秒,不是纳秒。不过我的工作站已经很老了,所以我们讨论的可能是每次解析不到 1 微秒的差异。
猜你喜欢
  • 1970-01-01
  • 2014-07-30
  • 1970-01-01
  • 2011-04-18
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
相关资源
最近更新 更多