Утечка памяти при повторном развертывании приложения в Tomcat - PullRequest
45 голосов
/ 17 октября 2011

При повторном развертывании приложения в tomcat возникает следующая проблема:

 The web application [] created a ThreadLocal with key of type
 [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@10d16b])
 and a value of type [com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty]
(value [com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty@1a183d2]) but 
 failed to remove it when the web application was stopped. 
 This is very likely to create a memory leak.

Также я использую ehcache в своем приложении. Это также может привести к следующему исключению.

     SEVERE: The web application [] created a ThreadLocal with key of type [null] 
     (value [com.sun.xml.bind.v2.ClassFactory$1@24cdc7]) and a value of type [java
     .util.WeakHashMap... 

Похоже, что ehcache создает слабую хеш-карту, и я получаю сообщение о том, что это может привести к утечке памяти.

Я искал по сети и нашел это, http://jira.pentaho.com/browse/PRD-3616 но у меня нет доступа к серверу как таковому.

Пожалуйста, дайте мне знать, если эти предупреждения имеют какое-либо функциональное влияние или их можно игнорировать? Я использовал опцию «Найти утечки памяти» в менеджере Tomcat, и она говорит: «Утечки памяти не найдены»

Ответы [ 5 ]

40 голосов
/ 17 октября 2011

При повторном развертывании приложения Tomcat создает новый загрузчик классов.Старый загрузчик классов должен быть подвергнут сборке мусора, в противном случае вы получите утечку памяти permgen.

Tomcat не может проверить, будет ли сборщик мусора работать, но он знает о нескольких типичных точках сбоев.Если загрузчик классов webapp устанавливает ThreadLocal с экземпляром, класс которого был загружен самим загрузчиком классов webapp, поток сервлета содержит ссылку на этот экземпляр.Это означает, что загрузчик классов не будет собирать мусор.

Tomcat делает несколько таких обнаружений, см. здесь для получения дополнительной информации .Очистка локальных потоков затруднена, вам придется вызывать remove() на ThreadLocal в каждом из потоков, к которым был получен доступ.На практике это важно только во время разработки, когда вы повторно развертываете свое веб-приложение несколько раз.В производственной среде вы, вероятно, не выполняете повторное развертывание, поэтому это можно игнорировать.

Чтобы действительно выяснить, какие экземпляры определяют локальные потоки, вы должны использовать профилировщик.Например, обходчик кучи в JProfiler (отказ от ответственности: моя компания разрабатывает JProfiler) поможет вам найти эти локальные потоки.Выберите класс сообщаемого значения (com.sun.xml.bind.v2.runtime.property.SingleElementLeafProperty или com.sun.xml.bind.v2.ClassFactory) и отобразите накопленные входящие ссылки.Одним из них будет java.lang.ThreadLocal$ThreadLocalMap$Entry.Выберите ссылочные объекты для этого входящего ссылочного типа и переключитесь в представление распределений.Вы увидите, где был размещен экземпляр.С этой информацией вы можете решить, можете ли вы что-то с этим сделать или нет.

enter image description here

7 голосов
/ 30 марта 2016

Маттиас Йидерхамн отлично статья из 6 частей , которая очень четко объясняет теорию и практику утечек в загрузчиках классов. Более того, он также выпустил файл jar, который мы можем включить в наши военные файлы. Я попробовал это в моих веб-приложениях, и файл jar работал как шарм! Файл jar называется classloader-leak -vention.jar. Чтобы использовать его так же просто, как просто добавить это в наш web.xml

<listener>
  <listener-class>se.jiderhamn.classloader.leak.prevention.ClassLoaderLeakPreventor</listener-class>
</listener>

, а затем добавьте это в наш pom.xml

<dependency>
  <groupId>se.jiderhamn</groupId>
  <artifactId>classloader-leak-prevention</artifactId>
  <version>1.15.2</version>
</dependency>

Для получения дополнительной информации, пожалуйста, обратитесь к Домашняя страница проекта, размещенная на GitHub или же Часть 6 его статьи

4 голосов
/ 10 сентября 2015

Создание потоков без их правильной очистки в конечном итоге приведет к тому, что вам не хватит памяти.

Те, кто все еще задается вопросом быстрого решения / обходного пути, могут выбрать следующее:

  • Если запущен автономный кот, убейте javaw.exe или процесс, несущий его.
  • При запуске из eclipse, уничтожить eclipse.exe и java.exe или включающий процесс.
  • Все еще не решен, Проверьте диспетчер задач, вполне вероятно, что процесс, вызывающий это, будетпоказывать с максимальным использованием памяти - Сделайте свой анализ и убейте это.
2 голосов
/ 26 июля 2013

Полагаю, вы, наверное, видели это, но на всякий случай ehcache doc рекомендует поместить библиотеку в tomcat, а не в WEB-INF / lib .

1 голос
/ 01 мая 2016

Я рекомендую инициализировать локальные потоки , в ServletRequestListener .

ServletRequestListener имеет 2 метода: один для инициализации и один для уничтожения.

Таким образом, вы можете очистить свой ThreadLocal. Пример:

public class ContextInitiator implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        context = new ThreadLocal<ContextThreadLocal>() {
            @Override
            protected ContextThreadLocal initialValue() {
                ContextThreadLocal context = new ContextThreadLocal();
                return context;
            }
        };
        context.get().setRequest(sre.getServletRequest());
    }
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        context.remove();
    }
}

web.xml:

<listener>
    <listener-class>ContextInitiator</listener-class>
</listener>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...