【问题标题】:tomcat thread local memory leaktomcat线程本地内存泄漏
【发布时间】:2012-05-29 18:55:01
【问题描述】:

我正在使用线程本地方法为每个应用程序线程创建一个 json 序列化程序,以避免每次我想序列化它时创建对象。

我使用的代码如下:

public class JsonSerializerFactory {
    private static final ThreadLocal<JsonSerializer> JSON_SERIALIZER = 
        new ThreadLocal<JsonSerializer>() {
        @Override 
        protected JsonSerializer initialValue() {
             return new JsonSerializer();
        }
    };

public static JsonSerializer get() {
    return JSON_SERIALIZER;
}

}

每次我想获得序列化程序时:

JsonSerializerFactory.get()

当我关闭 tomcat 时,我看到以下日志:

May 23, 2012 9:15:25 AM org.apache.catalina.loader.WebappClassLoader     clearReferencesThreads SEVERE: The web application [] appears to have started a thread named [Logback AsyncAppender Dispatcher [Async_Logger] - Thread-16] but has failed to stop it. This is very likely to create a memory leak.

我已经阅读了Tomcat memory leak protection,但我可能在那里遗漏了一些东西。 我真的有泄漏吗,还是应该忽略此消息?

谁能解释一下?

how to enhance tomcat thread pool behaviour

【问题讨论】:

  • tomcat 日志消息是指一个记录器(logback),而不是你的 JsonSerializer。您在此问题中引用的代码可能与您可能的内存泄漏问题无关。
  • 这个记录器在它的线程本地有一个 json 序列化器
  • Logback AsyncAppender?您必须使用自定义附加程序,因为截至今天 (2012-05-23) 没有 AsyncAppender 附带 logback。

标签: java tomcat memory-leaks thread-local


【解决方案1】:

我会说这与您的代码无关。

【讨论】:

    【解决方案2】:

    每次您使用ThreadLocal 时,您确实应该有一些方法来清除它。 tomcat 抱怨的是 logback 内部创建的线程在本地引用了这个线程,因此不会被收集(假设线程没有死)。

    如果出现以下情况,您可以忽略此消息:

    • 热应用程序重新加载并不那么重要,如果您重新加载应用程序,它只会泄漏
    • 您知道当应用程序停止时 logback 线程结束

    您可能首先要考虑的是是否需要ThreadLocal 缓存。 JsonSerializer 真的那么贵吗?你确定它不是线程安全的吗?

    public class JsonSerializerFactory {
        public static JsonSerializer get() {
            // do this until you know you have a problem.
            return new JsonSerializer();
        }
    }
    

    【讨论】:

    • 我实际上使用的是 Gson (1.7),我看到它在构造中有一些同步方法。我需要检查 2.2 版是否性能更好
    • 如果是性能问题,有没有好办法把它放到线程本地,并以某种方式增强tomcat Thread和threadFactory?
    • 从我对 Gson API 的了解来看,主要的 Gson 对象看起来应该是一个单例。使用您的序列化器/配置构建一次并将其用作单例。最新的手册说没有状态,所以应该是线程安全的
    • 如果我将其设为 bean,我会看到从 ParameterizedTypeHandlerMap.getHandlerFor 中的 toJson 方法调用的以下代码是同步的。这对我的运行时性能不利
    • 我已经对其进行了分析,并看到那里堆积了很多线程。但好消息是,对于 gson 2.1,我可以将其用作 bean,并且 toJson() 方法没有同步块。我只需要升级我的包版本。
    猜你喜欢
    • 1970-01-01
    • 2012-05-12
    • 2017-02-15
    • 1970-01-01
    • 2014-12-25
    • 1970-01-01
    • 2014-10-29
    • 2013-12-18
    • 2015-12-27
    相关资源
    最近更新 更多