У меня есть WebApplication, который развернут в Tomcat 7.0.70. Я смоделировал следующую ситуацию:
- Я создал кучу кучи.
- Затем я отправил запрос Http и в методе службы я напечатал текущий поток и его классLoader. И затем я вызвал Thread.currentThread.sleep(10000).
- И в тот же момент я нажал "undeploy это приложение" на странице администрирования Tomcat.
- Я создал новую кучу кучи.
- Через несколько минут я создал новый сброс hep.
Результаты
Дамп потока
На следующем экране вы можете увидеть, что после того, как я нажал "redeploy", все потоки (которые были связаны с этим веб-приложением) были убиты, за исключением потока "http-apr-8081-exec-10" . Когда я устанавливаю атрибут Tomcat "renewThreadsWhenStoppingContext == true", вы можете увидеть, что через некоторое время этот поток ( "http-apr-8081-exec-10" ) был убит и новый поток (http-apr-8081-exec-11 ) был создан вместо него. Поэтому я не ожидал наличия старого WCL после создания кучи dump 3, потому что нет старых потоков или объектов.
Сброс Heapd 1
На следующих двух экранах вы можете видеть, что при запуске приложения существовал только один WCL (его параметр "начал" = true). И в потоке "http-apr-8081-exec-10" был contextClassLoader = URLClassLoader (потому что он был в пуле Tomcat). Я говорю только об этом потоке, потому что вы сможете увидеть, что этот поток будет обрабатывать мой будущий HTTP-запрос.
Отправка HTTP-запроса
Теперь я отправляю HTTP-запрос, и в своем коде я получаю информацию о текущем потоке. Вы можете видеть, что мой запрос обрабатывается потоком "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]
Затем я нажимаю "Redeploy my web application", и я получаю следующее сообщение в консоли.
дек 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 dump 2
На следующих экранах видно, что есть два экземпляра WebAppClassLoader. Один из них (номер # 1) является старым (его атрибут "начал" = ложь). И WCL # 2 был создан после повторного развертывания приложения (его атрибут "начал" = true). И поток, который мы рассмотрим, имеет contextClassLoader = "org.apache.catalina.loader.WebappClassLoader". Зачем? Я ожидал увидеть contextClassLoader = "java.net.URLClassLoader" (в конце концов, когда любой поток заканчивает свою работу, он возвращается в пул Tomcat и его атрибут "contextClassLoader" установлен в любой загрузчик базового класса).
Heapd dump 3
Вы можете видеть, что нет потока "http-apr-8081-exec-10" , но есть поток "http-apr-8081-exec-11", и он имеет contextClassLoader = "WebappClassLoader",
(Почему бы не URLClassLoader?).
В итоге мы имеем следующее: есть поток "http-apr-8081-exec-11", который имеет ссылку на WebappClassLoader # 1. И obviosly, когда я делаю "Ближайший GC Root" на WCL # 1, я увижу ссылку ref в поток 11.
Вопросы.
Как я могу принудительно сказать Tomcat вернуть старое значение contextClassLoader (URLClassLoader) после того, как поток завершит свою работу?
Как я могу убедиться, что Tomcat не копирует старое значение "contextClassLoader" во время обновления потока?
Может быть, знаете ли вы другой способ решить мою проблему?