2017-01-18 3 views
20

У меня есть приложение WebApplication, которое развернуто в Tomcat 7.0.70. Я смоделировал следующую ситуацию:Утечка памяти при повторном развертывании приложения в Tomcat

  1. Я создал кучу кучи.
  2. Затем я отправил запрос Http и в методе службы я напечатал текущий поток и его классLoader. И затем я вызвал Thread.currentThread.sleep (10000).
  3. И в тот же момент я нажал «undeploy это приложение» на странице администрирования Tomcat.
  4. Я создал новую кучу кучи.
  5. Через несколько минут я создал новый сброс hep.


РЕЗУЛЬТАТЫ


свалка Thread

На следующем экране вы можете видеть, что после того, как я нажал "перераспределить", все потоки (которые были связаны с этим веб-приложением) были убиты, кроме потока «http-apr-8081-exec-10». Когда я установил атрибут Tomcat «renewThreadsWhenStoppingContext == true», вы можете увидеть, что через некоторое время этот поток («http-apr-8081-exec-10») был убит и новый поток (http-apr-8081-exec-11) был создан вместо него. Поэтому я не ожидал наличия старого WCL после создания кучи dump 3, потому что нет старых потоков или объектов.

enter image description here

Heapd свалка 1

На следующих двух экранах вы можете видеть, что, когда приложение бегала там был только один ВКТ (его параметр «начал» = истина). И в потоке «http-apr-8081-exec-10» был contextClassLoader = URLClassLoader (потому что он был в пуле Tomcat). Я говорю только об этой теме, потому что вы сможете увидеть, что этот поток будет обрабатывать мой будущий HTTP-запрос.

enter image description here

enter image description here

Отправка HTTP запрос

Теперь я отправить запрос HTTP и в моем коде я получаю информацию о текущем thread.You можно увидеть, что мой запрос обрабатывается резьбой «http-apr-8081-exec-10»

дек 23, 2016 9:28:16 AM c.c.c.f.s.r.ReportGenerationServiceImpl INFO: request has been handled in 
    thread = http-apr-8081-exec-10, its contextClassLoader = WebappClassLoader 
    context: /hdi 
    delegate: false 
    repositories: 
    /WEB-INF/classes/ 
    ----------> Parent Classloader: [email protected] 

Затем я нажимаю «Повторное развертывание своего веб-приложения», и я получаю следующее сообщение в консоли.

дек 23, 2016 9:28:27 AM org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads 
SEVERE: The web application [/hdi] appears to have started a thread named [http-apr-8081-exec-10] but has failed to stop it. This is very likely to create a memory leak. 

Heapd свалка 2

На следующих экранах вы можете видеть, что есть два экземпляра WebAppClassLoader. Один из них (номер # 1) является старым (его атрибут «начал» = ложь). И WCL # 2 был создан после повторного развертывания приложения (его атрибут «начал» = true). И нить, которую мы рассматриваем, имеет contextClassLoader = "org.apache.catalina.loader.WebappClassLoader". Почему? Я ожидал увидеть contextClassLoader = "java.net.URLClassLoader" (в конце концов, когда любой поток заканчивает свою работу, он возвращается в пул Tomcat , а его атрибут «contextClassLoader» устанавливается в любой загрузчик базового класса).

enter image description here

enter image description here

enter image description here

Heapd свалка 3

Вы можете увидеть, что там не поточно "HTTP-APR-8081-EXEC-10", но есть поток «http-apr-8081-exec-11», и у него есть contextClassLoader = «WebappClassLoader» (Почему бы не URLClassLoader?).

В конце концов, мы имеем следующее: есть поток «http-apr-8081-exec-11», который имеет ссылку на WebappClassLoader # 1. И obviosly когда я делаю "ближайший GC Root" на ВКТ # 1 Я буду видеть реф к потоку 11.

enter image description here

enter image description here

Вопросы.

Как я могу заставить Tomcat вернуть старое значение contextClassLoader (URLClassLoader) после того, как поток завершит свою работу?

Как я могу убедиться, что Tomcat не копирует старое значение «contextClassLoader» во время обновления потока?

Возможно, вы знаете другой способ решить мою проблему?

+0

Возможный дубликат [Threads in Tomcat. Утечки памяти] (http://stackoverflow.com/questions/41223141/threads-in-tomcat-memory-leaks) –

+0

Если вы не получили достаточного внимания в первый раз, возможно, вы могли бы начать щедрость. Не просто повторно отправляйте тот же вопрос снова. –

+0

@ ChristopherSchultz, этот пост дает больше информации. –

ответ

0

Утечка памяти при повторной установке tomcat - очень старая проблема. Единственный реальный способ решить это - перезагрузить tomcat вместо повторного развертывания приложения. Если у вас есть несколько приложений, вам нужно запустить несколько сервисов tomcat на разных портах и ​​присоединиться к нему с помощью nginx.

+0

Мы работаем с одним из серверов Java EE с 8 лет и **, мы написали процедуру, в которой сервер приложений перезапускается при каждом развертывании в рабочей среде **. – bilelovitch

3

Tomcat обычно не является хорошим вариантом в производственных условиях. Я использовал Tomcat для нескольких производственных приложений, и я обнаружил, что даже если размер кучи и другие конфигурации настроены правильно, и каждый раз, когда вы перезагружаете приложение, потребление памяти увеличивается и увеличивается. Пока вы не перезапустите службу tomcat, память не будет полностью восстановлена. Мы тестировали все такие эксперименты, такие как очистка журналов, передислокация всех приложений, регулярное перезапуск tomcat один раз в месяц или неделю в течение менее загруженных часов. Но в конце я должен сказать, что мы переместили нашу производственную среду на Glassfish и WebSphere.

Я надеюсь, что вы уже прошли через эти страницы:

Memory leak in a Java web application

Tomcat Fix Memory Leak?

https://developers.redhat.com/blog/2014/08/14/find-fix-memory-leaks-java-application/

http://www.tomcatexpert.com/blog/2010/04/06/tomcats-new-memory-leak-prevention-and-detection

Если ваши веб-приложения не являются тесно связанными с Tomcat, то вы можете думать об использовании anothe r веб-контейнер. Теперь мы используем Glassfish даже на машинах и производстве разработки, и в тот день, когда мы принимаем это решение, мы сэкономили много времени. Хотя Glassfish и другой такой сервер занимают больше времени, пока они начинаются, поскольку они не так легки, как Tomcat, но после того, как жизнь немного легче.

+0

Я согласен с вами в том, что это известная проблема Tomcat. Но мы все еще используем Tomcat в производстве, потому что он легкий и эффективный. Просто мы никогда не передислоцируем приложение на Tomcat, а просто перезапускаем контейнер tomcat. Это имеет смысл, потому что они являются очень популярными приложениями, и накладные расходы на контейнер приемлемы. –

0

У нас есть сотни экземпляров Tomcat, работающих в нескольких средах (также производство), и единственным разумным решением, которое мы нашли в этой проблеме, является остановка и перезапуск каждого Tomcat в установленное время ежедневно (в ночное время).

Мы пробовали много трюков, но это прочное решение для наших требований времени безотказной работы.

0

Tomcat обычно не является хорошим вариантом в производственных условиях. Я использовал Tomcat для нескольких производственных приложений, и я обнаружил, что даже если размер кучи и другие конфигурации настроены правильно, и каждый раз, когда вы перезагружаете приложение, потребление памяти увеличивается и увеличивается. Пока вы не перезапустите службу tomcat, память не будет полностью восстановлена. Мы тестировали все такие эксперименты, такие как очистка журналов, передислокация всех приложений, регулярное перезапуск tomcat один раз в месяц или неделю в течение менее загруженных часов. Но в конце я должен сказать, что мы переместили нашу производственную среду на Glassfish и WebSphere.

1

Из-за моего опыта с этой проблемой, что мешало tomcat должным образом GC старшим загрузчикам классов, было несколько фреймворков, которые я использовал, создавали (и не обрабатывали надлежащим образом).

Нечто похожее на то, что описано здесь: ThreadLocal & Memory Leak

Я попытался правильно завершить эту ThreadLocal с и мой утечки уменьшается МНОГО. Он все еще протекал, но я мог обрабатывать в 10 раз больше перераспределителей, чем раньше.

Я бы определенно проверил ваши дампы памяти на объекты, которые каким-то образом могут быть связаны с ThreadLocal (они очень распространены, особенно если вы используете что-то для управления транзакциями или что-то, что изолировано от потока).

Надеюсь, это поможет!

Смежные вопросы