我的开发人员和我在我们不想要它们时在我们的应用程序中收集垃圾的对象存在问题。我们在Weblogic 10g3中使用Java。我们正在编写单例模式来处理所有JMS连接。
涉及两个类:
public class JMSObject {
...
private MessageProducer _producer;
private MessageConsumer _consumer;
...
// standard get/set procs... etc.
}
public class JMSFactory {
...
// Hashmap sessions with key == ConnectionFactory Name
Hashmap<String, List<Session>> _sessions;
// Hashmap of JMSObjects with key == ConnectionFactory Name + JMS Queue Name
Hashmap<String, List<JMSObject>> _jmsobjects;
...
// standard get/set & necessary sington functions
}
Servlets的init方法调用JMSFactory singlton方法,任何新的Sessions都放在_sessions Hashmap中,新的MessageConsumer / MessageProducers作为JMSObject创建并放在_jmsobjects Hashmap中,位于相应的List中。
问题是当系统运行时,列表中的JMSObjects会在一段时间后收集垃圾(有时在几小时后的其他时间会收集5分钟。)我们查看了几天,但找不到任何理由为JMSObjects收集garbarge。既然JMSFactory有一个对它们的引用,为什么gc会破坏它们呢?
最后,我们通过更改类来修复它(不更改方法接口):
public class JMSObject {
...
private List<MessageProducer> _producers;
private List<MessageConsumer> _consumers;
...
// standard get/set procs... etc.
}
public class JMSFactory {
...
// Hashmap sessions with key == ConnectionFactory Name
Hashmap<String, List<Session>> _sessions;
// Hashmap of JMSObjects with key == ConnectionFactory Name + JMS Queue Name
private Hashmap<String JMSObject> _jmsobjects;
...
// standard get/set & necessary sington functions
}
到目前为止,在测试中JMSObjects并没有被gc'ed。它已经运行了2天。
有人可以解释为什么间接引用会导致JMSObject获取gc'ed吗?为什么_sessions Hashmap中的Sessions没有获得gc'ed?这与Sessions是用Javax类型构建的事实有什么关系,而JMSObject是我们写的东西吗?
答案 0 :(得分:5)
由于JMSFactory对它们有引用,为什么gc会破坏它们?
那么,此时是否还有任何对象仍然引用了JMSFactory?
典型的单例模式保持对静态成员中单例对象的引用:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
//constructor...
}
public static Singleton getInstance() { return instance; }
}
这不是你所遵循的模式吗?从您在帖子中提供的代码中无法判断,因为您遗漏了实际的单例代码......
(顺便说一句,使用单身人士这样的事情听起来会引起痛苦,除了难以测试之外。见Singletons Are Pathlogical Liars)
答案 1 :(得分:2)
我想我知道你的问题是什么,这是我在一段时间后遇到的事情(在WebLogic 6上)。我相信它与WebLogic的动态类重新加载有关,WebLogic似乎不时会这样做,即使你不在开发环境中(我猜测web.xml在某种程度上被某些服务或某些东西所触动) )。
在我们的案例中发生的事情是,像你一样,我们有一个对象的单个实例被定义为某个类的静态变量,就像你一样,它由一个具有它的load-on-startup参数的servlet初始化组。当WebLogic认为存在变化时,它通过垃圾收集类加载器(这很好)重新加载webapp 但是它不会重新初始化所有标记为“load-on-startup”的servlet(在我们的情况下,我猜你的,servlet除了初始化静态变量之外没有任何用途,没有映射到它,因此无法调用,静态变量得到GCed,但没有重新初始化,并且需要重启服务器。
在我们的例子中,我们的解决方案是在静态初始化程序中初始化静态变量。原始开发人员使用servlet来初始化变量,因为他想要一些servlet上下文信息,这实际上并不是必需的。如果您需要上下文信息,可以尝试在ServletContextListener中进行初始化。
答案 2 :(得分:1)
如果没有所有代码,这是一个难以解决的问题。但是有一些工具可以提供帮助。
试试此链接:http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ 它提供了有关使用jhat和jmap的信息。虽然本文是为了查找内存泄漏而编写的,但它提供了有关如何跟踪对象引用的信息。也许你可以找出你的参考文献消失的原因。
答案 3 :(得分:0)
你说_sessions地图中的会话不是GC,但是JMSObjects不是。我怀疑是因为这是你写的东西。听起来好像正在收集JMSFactory本身(即单例未正确实现)或者正在从地图中删除键。在任何一种情况下,JMSObjects都有资格使用GC,但会话对象不会,因为列表仍然有对它们的引用。
答案 4 :(得分:0)
加载JMSFactory的类加载器是否有可能被卸载,导致JMSFactory类被GC(包括单例实例),从而释放HashMaps及其内容?