这是来自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或其他容器中运行,该怎么办?
答案 0 :(得分:1)
单个jvm可以用作“应用程序服务器”。它托管容器,这些容器以“包”(例如EAR或WAR文件)的形式出现,可以动态地从jvm中添加/删除。
您可以通过使用类加载器的功能来实现。但是类加载器会跟踪它加载的所有类。因此,要释放旧的类加载器,必须忘记它知道的所有类。但这不能使单身人士做错事情。
或引用IBM:
一个对象保留对其作为实例的类的引用。一个类保留对加载它的类加载器的引用。类加载器保留对其加载的每个类的引用。保留对Web应用程序中单个对象的引用会固定Web应用程序加载的每个类。这些引用通常在重新加载Web应用程序后仍然保留。每次重新加载时,都会固定更多类,从而导致内存不足错误
应OP的要求,我尝试查找“坏”或“有效”单例实现的示例,但找不到任何示例。
但是要换一个角度来看:由于我们有枚举,因此可以使用枚举来实现单例(请参阅here)。因此,今天的合理答案可能是:只需使用枚举即可。鉴于在互联网上没有太多关于此主题的事实,我(个人)的直觉是:这根本不再是现实世界中的相关问题。