首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Tomcat中重新部署应用程序时内存泄漏

在Tomcat中重新部署应用程序时内存泄漏
EN

Stack Overflow用户
提问于 2017-01-18 12:01:43
回答 6查看 7.6K关注 0票数 24

我有WebApplication,它部署在Tomcat7.0.70中。我模拟了以下情况:

  1. 我创建了堆转储。
  2. 然后,我发送了Http请求,在服务的方法中,我打印了当前线程及其classLoader。然后我调用了Thread.currentThread.sleep(10000)。
  3. 同时,我在Tomcat的管理页面中单击“取消部署此应用程序”。
  4. 我创建了新的堆转储。
  5. 几分钟后,我创建了新的hep转储。

结果

线程转储

在下面的屏幕上,您可以看到,在我单击“重新部署”之后,除了线程"http-apr-8081-exec-10“之外,所有线程(与此web应用程序相关联)都被杀死。当我设置Tomcat的属性"renewThreadsWhenStoppingContext == true“时,您可以看到,经过一段时间之后,这个线程(”http 8081-exec-10“)被杀死,新线程(http 8081-exec-11)被创建。因此,我没想到在创建堆转储3之后会有旧的WCL,因为没有任何旧的线程或对象。

头转储1

在下面两个屏幕上,您可以看到,当应用程序运行时,只有一个WCL(其参数"started“= true)。线程"http-apr-8081-exec-10“的contextClassLoader = URLClassLoader (因为它在Tomcat的池中)。我只谈论这个线程,因为您将能够看到这个线程将处理我未来的HTTP请求。

发送HTTP请求

现在我发送了HTTP请求,在我的代码中我得到了关于当前thread.You的信息,可以看到我的请求正在由线程"http-apr-8081-exec-10“处理。

代码语言:javascript
复制
дек 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: java.net.URLClassLoader@4162ca06

然后单击“重新部署我的web应用程序”,然后在控制台中得到以下消息。

代码语言:javascript
复制
 дек 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.

堆转储2

在下面的屏幕上,您可以看到有两个实例WebAppClassLoader。其中一个(编号#1)是旧的(它的属性"started“= false)。WCL #2是在重新部署应用程序之后创建的(它的属性"started“= true)。我们审查的线程有contextClassLoader =contextClassLoader为什么?我希望看到contextClassLoader = "java.net.URLClassLoader“(毕竟,当任何线程完成其工作时,它将返回到Tomcat的池中,其属性"contextClassLoader”被设置为任何基类加载程序)。

头转储3

您可以看到没有线程"http-apr-8081-exec-10",但是有线程"http-apr-8081-exec-11“,并且它有contextClassLoader = "WebappClassLoader”(为什么不是URLClassLoader?)。

最后,我们有以下内容:有线程"http-apr-8081-exec- 11“,它具有指向WebappClassLoader #1的引用。而且,显然,当我在WCL #1上创建”最近的GC根“时,我将看到线程11的引用。

问题.

在线程完成它的工作后,我如何强制地对Tomcat说返回旧值contextClassLoader (URLClassLoader)?

如何确保Tomcat在线程更新期间不复制旧值"contextClassLoader“?

也许,你知道其他解决我问题的方法吗?

EN

回答 6

Stack Overflow用户

发布于 2017-09-20 15:24:46

在生产环境中,Tomcat通常不是一个很好的选择。我在一些生产应用程序上使用Tomcat,我发现即使堆大小和其他配置设置正确-而且每次重新加载应用程序时,内存消耗都会不断增加。除非您不重新启动tomcat服务,否则内存不会完全恢复。我们对所有这样的实验进行了测试,比如清除日志,重新部署所有应用程序,每个月或至少在繁忙时间定期重启tomcat一次。但最后,我不得不说,我们的生产环境已经转向玻璃鱼和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

如果您的web应用程序没有与Tomcat紧密耦合,那么您可以考虑使用另一个web容器。现在我们甚至在开发机器和生产上使用玻璃鱼,在我们做出这个决定的那一天,我们节省了很多时间。尽管Glassfish和其他类似的服务器需要更多的时间来启动,因为它们并不像Tomcat那样轻量级,但是在生活之后就会变得更加简单。

票数 10
EN

Stack Overflow用户

发布于 2017-09-22 08:50:37

从我处理这个问题的经验来看,阻止tomcat正确地GC类装入器的原因是我正在创建(而不是正确处理)一些ThreadLocal的几个框架。

类似于这里所解释的内容:ThreadLocal & Memory Leak

我试图正确地完成这个ThreadLocal,我的泄漏减少了很多。它还在漏水,但我可以处理比以前多10倍的重新部署。

我肯定会检查您的内存转储到可以以某种方式连接到ThreadLocals的对象(它们非常常见,特别是如果您使用一些东西来控制事务或线程隔离的任何东西)。

希望能帮上忙!

票数 2
EN

Stack Overflow用户

发布于 2017-09-16 09:00:04

tomcat重新部署中的内存泄漏是一个非常老的问题。解决这个问题的唯一真正方法是重新启动tomcat,而不是重新部署应用程序。如果您有几个应用程序,您需要在不同的端口上运行几个tomcat的服务,并使用nginx连接它。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41718907

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档