1

我和我的开发人员在我们不希望对象被垃圾回收时遇到了问题。我们将 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 方法,任何新的 Session 都被放置在 _sessions Hashmap 中,新的 MessageConsumer/MessageProducers 被创建为 JMSObject 并放置在 _jmsobjects Hashmap 中的适当列表中。

问题是当系统运行时,列表中的 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 中的 Sessions 没有被 gc'ed?这与 Session 是用 Javax 类型构建的,而 JMSObject 是我们编写的东西有关吗?

4

5 回答 5

5

既然 JMSFactory 引用了它们,为什么 gc 会销毁它们?

那么,此时是否有任何对象仍然持有对 JMSFactory 的引用?

典型的单例模式将单例对象的引用保存在静态成员中:

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

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

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

这不是您遵循的模式吗?无法从您在帖子中提供的代码中分辨出来,因为您遗漏了实际的单例代码......

(顺便说一句,将单例用于这样的事情听起来会引起痛苦,除了难以测试。请参阅单例是病态的骗子

于 2009-07-14T03:16:01.053 回答
2

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

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

在我们的例子中,我们的解决方案是在静态初始化器中初始化静态变量。最初的开发人员使用 servlet 来初始化变量,因为他想要一些 servlet 上下文信息,而这实际上是不必要的。如果您需要上下文信息,您可以尝试在ServletContextListener中进行初始化。

于 2009-07-14T04:25:39.120 回答
1

如果没有所有代码,这是一个很难解决的问题。但是有一些工具可以提供帮助。

试试这个链接:http : //blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ 它提供了有关使用 jhat 和 jmap 的信息。尽管这篇文章是为查找内存泄漏而编写的,但它提供了有关如何跟踪对对象的引用的信息。也许您可以找出您的参考资料消失的原因。

于 2009-07-14T03:25:17.027 回答
0

您说 _sessions 映射中的 Sessions 没有被 GC,但 JMSObjects 没有。我怀疑这是因为它是你写的东西。听起来像是 JMSFactory 本身正在被收集(即单例未正确实现),或者某些东西正在从地图中删除键。在任何一种情况下,JMSObjects 都符合 GC 条件,但会话对象不符合条件,因为列表仍然有对它们的引用。

于 2009-07-14T03:19:05.463 回答
0

加载 JMSFactory 的类加载器是否有可能被卸载,导致 JMSFactory 类被 GC(包括单例实例),从而释放 HashMap 及其内容?

于 2009-07-14T03:42:00.487 回答