关闭Java EE应用程序时,内存泄漏无法卸载Singletons

时间:2019-01-01 14:50:05

标签: java java-ee memory-leaks singleton

这是来自StackOverflow的高发example内存泄漏:

  

在关闭Java EE应用程序时不卸载单例 。显然,加载单例类的Classloader将保留对该类的引用,因此单例实例将永远不会被收集。部署应用程序的新实例时,通常会创建一个新的类加载器,并且由于单例的原因,以前的类加载器将继续存在。

1)我不明白如何“ 卸载”单例,以及“ 分解Java EE应用程序”的含义。您能否提供代码示例(错误的代码示例和正确的代码示例)和方案?

2)来自same stackoverflow帖子:

  

获取在任何servlet容器(Tomcat,Jetty,Glassfish等)中运行的任何Web应用程序。连续10或20次重新部署该应用程序(仅在服务器的自动部署目录中触摸WAR即可。

     

除非有人对此进行了实际测试,否则您很可能会   经过几次重新部署后会收到OutOfMemoryError,因为   应用程序没有照顾自己后进行清理。你甚至可能   通过此测试在您的服务器中找到错误。

     

问题是,容器的寿命比   应用程序的生命周期。 您必须确保所有   容器可能必须引用您的对象或类   可以对应用程序进行垃圾收集。

     

如果只有一个引用幸免于您的Web应用的取消部署,则相应的类加载器以及所有结果   您的Web应用程序的类不能被垃圾收集。

     

应用程序启动的线程,ThreadLocal变量,日志记录   附加程序是导致类加载器泄漏的常见嫌疑犯。

我无法理解容器(Tomcat类/对象)如何保存对应用程序的对象或类的引用,这是我的错。自动内存管理意味着我不必担心释放内存,对吗?那么,如果我的应用程序在Tomcat或其他容器中运行,该怎么办?

1 个答案:

答案 0 :(得分:1)

单个jvm可以用作“应用程序服务器”。它托管容器,这些容器以“包”(例如EAR或WAR文件)的形式出现,可以动态地从jvm中添加/删除。

您可以通过使用类加载器的功能来实现。但是类加载器会跟踪它加载的所有类。因此,要释放旧的类加载器,必须忘记它知道的所有类。但这不能使单身人士做错事情。

或引用IBM

  

一个对象保留对其作为实例的类的引用。一个类保留对加载它的类加载器的引用。类加载器保留对其加载的每个类的引用。保留对Web应用程序中单个对象的引用会固定Web应用程序加载的每个类。这些引用通常在重新加载Web应用程序后仍然保留。每次重新加载时,都会固定更多类,从而导致内存不足错误

应OP的要求,我尝试查找“坏”或“有效”单例实现的示例,但找不到任何示例。

但是要换一个角度来看:由于我们有枚举,因此可以使用枚举来实现单例(请参阅here)。因此,今天的合理答案可能是:只需使用枚举即可。鉴于在互联网上没有太多关于此主题的事实,我(个人)的直觉是:这根本不再是现实世界中的相关问题。