为什么这是垃圾收集

问题描述:

我的开发人员和我有一个问题,当我们不希望他们成为垃圾收集在我们的应用程序中的对象。我们正在使用Java和Weblogic 10g3。我们正在编写一个单例模式来处理我们所有的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 
} 

的servlet的init方法调用JMSFactory singlton方法,任何新的会话被放置在_sessions HashMap和新的MessageConsumer /的MessageProducer被创建为JMSObject并放置在_jmsobjects Hashmap中,在适当的List中。

问题是,当系统运行时,列表中的JMSObjects会在一段时间后收集垃圾(有时在几个小时后的其他时间5分钟内)。我们查看了几天,但找不到任何JMSObjects被收集的理由。由于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中的会话没有得到gc'ed?它与Sessions是否构建在Javax类型中并且JMSObject是我们写的东西有什么关系?

+0

当JMSObject被垃圾回收时,我认为它的大小保持不变,但是当你尝试读取它时会得到`null`s? – 2009-07-14 03:18:38

+0

@Jack Leow,是NullPointerException ... :-( – beggs 2009-07-14 04:33:06

我想我知道你的问题是什么,这是我后来遇到的问题(在WebLogic 6上)。我相信这与WebLogic的动态类重新加载有关,即使您不在开发环境中,WebLogic似乎也会这样做(我猜web.xml有些被某些服务或某种东西所触动)。

我们的情况发生了什么,就像你一样,我们有一个对象的单个实例,它被定义为某个类的静态变量,就像你一样,它由一个servlet初始化,它具有启动时加载参数集。当WebLogic认为有变化时,它通过垃圾收集类加载器(很好)但是重新加载webapp,它不会重新初始化所有标记为“load-on-startup”的servlet(在我们的例子中,以及我猜你的是,servlet除了初始化静态变量,没有映射到它之外,没有其他用途,所以它不能被调用,静态变量被GCed,但不被重新初始化,并且服务器需要被重新启动

在我们的例子中,我们的解决方案是在静态初始化器中初始化静态变量,原始开发者使用servlet初始化变量,因为他想要一些servlet上下文信息,如果你真的没有必要的话。需要上下文信息,你可以尝试在ServletContextListener中进行初始化。

由于JMSFactory有一个引用他们为什么gc会摧毁他们?

那么,在这一点上,任何对象仍然保留引用JMSFactory?

典型的单件模式保持在一个静态成员的参考singleton对象:

public class Singleton { 
    private static Singleton instance = new Singleton(); 

    private Singleton() { 
     //constructor... 
    } 

    public static Singleton getInstance() { return instance; } 
} 

这是不是你下的格局?从你的帖子中提供的代码是不可能告诉你的,因为你遗漏了实际的单身代码...

(顺便说一句,使用单身人士来说这样的事情听起来像会引起痛苦,除了很难测试。请参阅Singletons Are Pathlogical Liars

+0

@matt b ...是的,事情是静态的,略有不同的代码(我们在构造函数中实例化单例,但变量是静态的)有趣的文章,感谢链接 – beggs 2009-07-14 04:38:22

您说_sessions映射中的会话不是GC'd,但JMSObjects不是。我怀疑这是因为它是你写的东西。这听起来像是JMSFactory本身正在被收集(即singleton没有正确实现),或者是从地图中删除了键。无论哪种情况,JMSObjects都有资格使用GC,但会话对象不会因为该列表仍然有对它们的引用。

没有所有的代码,这是一个棘手的问题要解决。但有些工具可以帮助你。

尝试此链接:http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ 它提供了有关使用jhat和jmap的信息。尽管文章是为了查找内存泄漏而编写的,但它提供了有关如何跟踪对象引用的信息。也许你可以追查为什么你的参考文献正在消失。

任何加载JMSFactory的类加载器都被卸载,导致JMSFactory类被GC化(包括单例实例),从而释放HashMaps及其内容?