【问题标题】:Threadlocal memory leak in Threadpool线程池中的线程本地内存泄漏
【发布时间】:2012-05-12 00:11:24
【问题描述】:

我在 Tomcat 中遇到线程本地内存泄漏错误,我正在使用 ThreadPool,但在我的 web 应用程序中没有实现 ThreadLocal。

严重:Web 应用程序 [/myWebApp] 创建了一个 ThreadLocal,其键类型为 [org.a pache.http.impl.cookie.DateUtils$DateFormatHolder$1](值 [org.apache.http.imp l.cookie.DateUtils$DateFormatHolder$1@4c2849]) 和类型为 [java.lang.re f.SoftReference] (值 [java.lang.ref.SoftReference@1e67280])但未能 rem 当 Web 应用程序停止时就停止使用它。线程将被更新 是时候尝试避免可能的内存泄漏了。

我不明白为什么我没有实现线程本地错误?我想摆脱这些消息,所以我搜索了网络,并在here 中写道,为了清理我需要使用的线程本地:

ThreadLocal.remove()

但我没有 ThreadLocal 的实现。如果有人告诉我一个方法,我将不胜感激。

【问题讨论】:

  • 您可能正在您的应用程序中创建线程。当 servlet 关闭/重新启动时,您是否尝试过销毁/清理它们?通常不建议在 JEE 环境中自己启动 Threads,而是使用 Quartz 之类的框架
  • 是的,我正在创建线程,但我正在将它们添加到池中。完成后,我关闭了线程池执行程序。

标签: java tomcat thread-local threadpool


【解决方案1】:

显然,something 正在创建那个/那些 ThreadLocal 实例。如果不是您的代码,那么它一定是您正在使用的某个库,或者(不太可能)Tomcat 本身。

我将首先查看可能创建的实例

    org.apache.http.impl.cookie.DateUtils$DateFormatHolder$1

(顺便说一句,这是DataUtils 中嵌套类中的匿名类......所以除非发生奇怪的事情,否则创建将发生在DateUtils.java 文件中。)

如果检查源代码没有帮助,请尝试调试 Tomcat 实例并在 ThreadLocal 构造函数上设置断点。

【讨论】:

    【解决方案2】:

    问题出在您的第三方库中。您不能在线程池环境中使用线程局部变量,除非您在每个请求结束后真正清理它们。

    这篇文章解释了这个问题: http://blog.maxant.co.uk/pebble/2008/09/23/1222200780000.html

    【讨论】:

    • 我要补充的不是因为你在运行自己的线程池,而是因为第三方污染了tomcat运行所有传入http请求的“本机”线程池。跨度>
    【解决方案3】:

    ThreadLocal 显然是由您使用的某个框架或库创建的(看看哪个使用了HttpClient),但正如您在日志中看到的那样,该值是一个 SoftReference,它应该可以最大限度地减少内存泄漏。

    事实上,您可以在 code for DateUtils 中看到它正在创建 Threadlocal...

    【讨论】:

    • 虽然 SoftReference 可以最大限度地减少泄漏,但它不会解决它。 ThreadLocal 现在绑定到类加载器,所以热部署会导致 OOM permagen。
    【解决方案4】:

    这里是 HttpClient JIRA:https://issues.apache.org/jira/browse/HTTPCLIENT-1216

    从 4.2.2 版开始,有一个 clearThreadLocal() 方法,从 4.3 开始,cookie-DateUtils 已被弃用,取而代之的是 org.apache.http.client.utils.DateUtils。

    在关闭时调用 DateUtils.clearThreadLocal() 一次是不够的,它只会清除当前线程的 ThreadLocal,因此您需要在该线程上执行解析/格式化日期的 HTTP 请求后调用它。不过,这消除了使用 ThreadLocal 的大部分性能优势。

    或者,如果您从您控制的线程(不是由 Tomcat 创建)执行 HTTP 请求,请记住在应用程序关闭时关闭所有线程池/执行程序。

    遗憾的是,HttpClient 可以很容易地修改为不覆盖 ThreadLocal,然后 ThreadLocal 不会引用 webapp 及其类加载器,从而避免了我相信的大部分泄漏:(

    【讨论】:

    • 更新:据说在 httpclient 4.5.x 4.5.1 之后修复。关于避免覆盖 ThreadLocal,因为 Java 8 有 ThreadLocal.withInitial(Supplier) 但是它引用了您的 Supplier 实现,这反过来将拉入 webapp 的类加载器和“一切”。
    猜你喜欢
    • 1970-01-01
    • 2015-05-20
    • 2012-05-29
    • 2017-12-07
    • 2018-12-18
    • 2014-12-30
    • 2014-10-29
    • 2013-12-18
    • 2017-02-04
    相关资源
    最近更新 更多