简体   繁体   English

关闭 Java EE 应用程序时内存泄漏不会卸载单例

[英]Memory leak not unloading Singletons when bringing down a Java EE application

This is a high-voted example of memory leak from StackOverflow:这是 StackOverflow 内存泄漏的一个高票示例

Not unloading Singletons when bringing down a Java EE application .在关闭 Java EE 应用程序时不卸载 Singleton Apparently, the Classloader that loaded the singleton class will retain a reference to the class, and hence the singleton instance will never be collected.显然,加载单例类的类加载器将保留对该类的引用,因此永远不会收集单例实例。 When a new instance of the application is deployed, a new class loader is usually created, and the former class loader will continue to exist due to the singleton.当应用程序的新实例被部署时,通常会创建一个新的类加载器,由于单例,以前的类加载器将继续存在。

1) I do not understand how can I " unload " a singleton and what is meant by " bringing down a Java EE application ". 1) 我不明白如何“卸载”单例以及“关闭 Java EE 应用程序”是什么意思。 Could you provide code examples (wrong and right code samples) and scenarios?你能提供代码示例(错误和正确的代码示例)和场景吗?

2) From the same stackoverflow post: 2)来自同一个stackoverflow帖子:

Take any web application running in any servlet container (Tomcat, Jetty, Glassfish, whatever...).使用在任何 servlet 容器(Tomcat、Jetty、Glassfish 等等)中运行的任何 Web 应用程序。 Redeploy the app 10 or 20 times in a row (it may be enough to simply touch the WAR in the server's autodeploy directory.连续重新部署应用程序 10 或 20 次(只需触摸服务器自动部署目录中的 WAR 就足够了。

Unless anybody has actually tested this, chances are high that you'll get an OutOfMemoryError after a couple of redeployments, because the application did not take care to clean up after itself.除非有人对此进行过实际测试,否则在几次重新部署后您很可能会遇到 OutOfMemoryError,因为应用程序没有注意自行清理。 You may even find a bug in your server with this test.通过此测试,您甚至可能会发现服务器中的错误。

The problem is, the lifetime of the container is longer than the lifetime of your application.问题是,容器的生命周期比应用程序的生命周期长。 You have to make sure that all references the container might have to objects or classes of your application can be garbage collected.您必须确保容器对应用程序的对象或类可能具有的所有引用都可以被垃圾收集。

If there is just one reference surviving the undeployment of your web app , the corresponding classloader and by consequence all classes of your web app cannot be garbage collected.如果只有一个引用在您的 Web 应用程序卸载后幸存下来,则相应的类加载器以及您的 Web 应用程序的所有类都无法被垃圾收集。

Threads started by your application, ThreadLocal variables, logging appenders are some of the usual suspects to cause classloader leaks.由您的应用程序启动的线程、ThreadLocal 变量、日志附加程序是导致类加载器泄漏的一些常见嫌疑人。

I cannot understand how is it possible that container (Tomcat classes/objects) holds references to objects or classes of my application and it is my fault.我无法理解容器(Tomcat 类/对象)怎么可能保存对我的应用程序的对象或类的引用,这是我的错。 Automatic memory management means I don't have to care about freeing memory, right?自动内存管理意味着我不必关心释放内存,对吗? So what shall I take care of if my application runs within Tomcat or another container?那么,如果我的应用程序在 Tomcat 或其他容器中运行,我应该注意什么?

A single jvm can be used as "application server".单个 jvm 可以用作“应用程序服务器”。 It hosts containers, coming in as "packages" (EAR or WAR files for example) that can be dynamically added / removed from the jvm.它托管容器,作为“包”(例如 EAR 或 WAR 文件)进入,可以从 jvm 中动态添加/删除。

You achieve that by using the capabilities of the class loader.您可以通过使用类加载器的功能来实现这一点。 But a class loader keeps track of all the classes it loaded.但是类加载器会跟踪它加载的所有类。 So, to free up the old class loader it has to forget all classes it knows about.因此,要释放旧的类加载器,它必须忘记它知道的所有类。 But it can't for singletons done wrong.但它不能用于做错的单身人士。

Or quoting from IBM :或引用IBM

An object retains a reference to the class it is an instance of.对象保留对它是其实例的类的引用。 A class retains a reference to the class loader that loaded it.类保留对加载它的类加载器的引用。 The class loader retains a reference to every class it loaded.类加载器保留对其加载的每个类的引用。 Retaining a reference to a single object from a web application pins every class loaded by the web application.保留对来自 Web 应用程序的单个对象的引用固定 Web 应用程序加载的每个类。 These references often remain after a web application reload.这些引用通常在 Web 应用程序重新加载后保留。 With each reload, more classes are pinned which leads to an out of memory error每次重新加载时,都会固定更多类,从而导致内存不足错误

By request from the OP, I tried to find examples for "bad" respectively "working" singleton implementations, but I couldn't find any.应 OP 的要求,我试图找到“坏”和“工作”单例实现的示例,但找不到任何示例。

But to give a different perspective: since we have enums, we can use enums to implement a singleton (see here ).但是换个角度看:既然我们有枚举,我们可以使用枚举来实现单例(参见这里)。 So, probably the reasonable answer today is: simply use enums.所以,今天的合理答案可能是:简单地使用枚举。 And given the fact that there isn't much to find on the internet regarding this subject, my (personal) gut feeling is: this is simply not a relevant problem in the real world (any more).鉴于互联网上关于这个主题的内容不多,我的(个人)直觉是:这在现实世界中根本不是一个相关的问题(不再)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM