我正在调试一个我在Tomcat应用程序中多年来遇到的问题——由于Webapp类加载器无法通过气相色谱重新启动应用程序时导致的内存泄漏。我用JProfiler对堆进行了快照,似乎至少我的一些静态变量没有被释放。
某些类有一个静态 final 成员,该成员在首次加载类时初始化,并且因为它是 final,所以我无法在应用程序关闭时将其设置为 null。
静态最终变量是Tomcat中的反模式,还是我错过了什么?我刚刚开始使用JProfiler 8,所以我可能误解了传入引用告诉我的内容。
干杯!
卢克
此博客可以让你了解应用程序中的内存泄漏。
当类本身被垃圾收集时,静态变量应该被垃圾收集,反过来,当它的类加载器被垃圾收集时也是如此。
您可以通过让应用程序类加载器未加载的任何内容具有对任何类(或类的实例)的引用来轻松创建内存泄漏。查找您没有正确删除的回调侦听器等内容(内部/匿名类很容易被忽略)。
对某个类的单个引用会阻止其类加载器,进而阻止该类加载程序加载的任何类被垃圾收集。
编辑,泄漏阻止所有类GC的对象的示例:
MemoryMXBean mx = ManagementFactory.getMemoryMXBean();
NotificationListener nl = new NotificationListener() { ... };
((NotificationEmitter) mx).addNotificationListener(nl, ..., ...);
如果您使用存在于应用程序范围之外的对象(此处为MemoryMXBean)注册侦听器(此处为NotificationListener),则侦听器将保持“活动”状态,直到显式删除它。由于您的侦听器实例持有对其ClassLoader(您的应用程序类加载器)的引用,因此您现在创建了一个强引用链,以防止类加载者的GC,进而阻止它加载的所有类,并通过它阻止这些类持有的任何静态变量。
编辑2:基本上你需要避免这种情况:
[Root ClassLoader]
|
v
[Application ClassLoader]
|
v
(Type loaded by Root).addSomething()
运行应用程序服务器的JVM已经通过根类加载器(也可能是应用程序服务器)加载了JRE。这意味着这些类永远不会符合GC的条件,因为总会有对其中一些类的实时引用。应用程序服务器将在一个单独的类加载器中加载应用程序,在重新部署应用程序时(或者至少应该),它将不再保存对该类的引用。但是您的应用程序将与应用程序服务器(至少是JRE,但通常也是应用程序服务器)共享至少来自JRE的所有类。
假设应用服务器要创建一个单独的类加载器(没有父类,实际上是第二个根类加载器)并尝试第二次加载JRE(作为应用程序的私有对象),这会导致很多问题。旨在成为单例的类将会存在两次,并且这两个类的层次结构将无法保存对另一个类的任何引用(这是由不同的类装入器装入的相同的类对于JVM来说是不同的类型造成的)。他们甚至不能使用java.lang.Object作为各自“其他”类加载器对象的引用类型。
这是几年前的事情,但我在JavaOne上做的这篇演讲正好涵盖了这个主题。发现泄漏的关键步骤在幻灯片11中,但有很多背景信息可能也很有用。
简短的版本是:
正如我在演示文稿中指出的,找到泄漏是一回事,找到触发泄漏的原因可能要困难得多。
我建议在最新的稳定 Tomcat 版本上运行,因为我们一直在改进内存泄漏检测和预防代码,并且生成的警告和错误也可能提供一些指针。
我的tomcat日志中有这些消息: “org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc web应用程序注册了JBDC驱动程序[com.mysql.jdbc.driver],但在web应用程序停止时未能注销它。为了防止内存泄漏,已强制注销jdbc驱动程序。” 和 “org.apache.catalina.loader.W
问题内容: 由于Tomcat中的孤立线程,我遇到了内存泄漏。特别是,Guice和JDBC驱动程序似乎没有关闭线程。 我知道这与其他问题,但是就我而言,“不必担心”的答案是不够的,因为它给我带来了麻烦。我的CI服务器会定期更新此应用程序,重新加载6-10次后,由于Tomcat内存不足,CI服务器将挂起。 我需要能够清理这些孤立的线程,以便可以更可靠地运行CI服务器。任何帮助,将不胜感激! 问题答案:
问题内容: 我已经定义了一个对象并声明了一个静态变量。在该方法中,当我尝试打印实例和类变量时,两者都打印相同的值。 不是实例变量吗?它应该打印0而不是50吗? 问题答案: 不,只有一个变量-您尚未声明任何实例变量。 不幸的是,Java允许您访问静态成员,就像通过相关类型的引用访问静态成员一样。这是IMO的设计缺陷,某些IDE(例如Eclipse)允许您将其标记为警告或错误- 但这是语言的一部分。您
问题内容: 如果我的应用程序具有太多的静态变量或方法,则按照定义,它们将存储在堆中。如果我错了请指正我 1)这些变量会在应用程序关闭之前一直在堆上吗? 2)他们随时可以用于GC吗?如果不能,那是内存泄漏吗? 问题答案: 静态方法只是方法,它们不存储在堆中,只是不使用“ this”参数。 静态变量充当GC的“根”。结果,除非您将它们显式设置为null,否则它们将一直存在,只要程序处于活动状态,那么它
静态变量 PHP中局部变量分配在zend_execute_data结构上,每次执行zend_op_array都会生成一个新的zend_execute_data,局部变量在执行之初分配,然后在执行结束时释放,这是局部变量的生命周期,而局部变量中有一种特殊的类型:静态变量,它们不会在函数执行完后释放,当程序执行离开函数域时静态变量的值被保留下来,下次执行时仍然可以使用之前的值。 PHP中的静态变量通过
本文向大家介绍PHP静态成员变量和非静态成员变量详解,包括了PHP静态成员变量和非静态成员变量详解的使用技巧和注意事项,需要的朋友参考一下 数据成员可以分静态变量、非静态变量两种. 静态成员:静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会分配内存,所以静态成员不能访问非静态的成员..因为静态成员存在于