My developers and I are having an issue with objects being garbage collected in our application when we don't want them to be. We are using Java with Weblogic 10g3. We are programming a singleton pattern to handle all of our JMS connections.
我和我的开发人员遇到了一个问题,当我们不想要它们时,我们的应用程序中的对象被垃圾收集。我们在Weblogic 10g3中使用Java。我们正在编写单例模式来处理所有JMS连接。
There are two classes involved:
涉及两个类:
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
}
The init method of the Servlets calls the JMSFactory singlton method, any new Sessions are placed in the _sessions Hashmap and new MessageConsumer/MessageProducers are created as a JMSObject and placed in the _jmsobjects Hashmap, in the appropriate List.
Servlet的init方法调用JMSFactory单元方法,任何新的Sessions都放在_sessions Hashmap中,新的MessageConsumer / MessageProducers作为JMSObject创建,并放在_jmsobjects Hashmap中的相应List中。
The problem is that when the system is running the JMSObjects in the list get garbage collected after some time (sometimes in 5 minutes other times after a few hours.) We looked at this for a few days but could not find any reason for the JMSObjects to be garbarge collected. Since the JMSFactory has a reference to them why would the gc destroy them?
问题是,当系统运行时,列表中的JMSObjects会在一段时间后收集垃圾(有时在几小时后的其他时间会收集5分钟。)我们查看了几天,但找不到任何JMSObjects的原因被收集的野蛮人。既然JMSFactory引用了它们,为什么gc会破坏它们呢?
In the end we fixed it by changing the classes as follows(without changing method interfaces):
最后,我们通过更改类来修复它(不更改方法接口):
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
}
So far in testing the JMSObjects are not being gc'ed. It has been running for 2 days.
到目前为止,在测试中JMSObjects并没有被gc'ed。它已经运行了2天。
Can someone explain why the indirect reference is causing the JMSObject to get gc'ed? And why the Sessions in the _sessions Hashmap was not getting gc'ed? Does it have anything to do with the fact the Sessions are built in Javax types and the JMSObject is something we wrote?
有人可以解释为什么间接引用导致JMSObject获取gc'ed?为什么_sessions Hashmap中的Sessions没有获得gc'ed?它与Sessions是用Javax类型构建的事实有什么关系,而JMSObject是我们写的东西吗?
5 个解决方案
#1
I think I know what your problem is, it's something I ran into a while back (on WebLogic 6). I believe it has to do with WebLogic's dynamic class reloading, which WebLogic seems to do from time to time, even when you're not in a development environment (I'm guessing the web.xml is somehow getting touched by some service or something).
我想我知道你的问题是什么,这是我在一段时间后遇到的事情(在WebLogic 6上)。我相信它与WebLogic的动态类重新加载有关,WebLogic似乎不时会这样做,即使你不在开发环境中(我猜测web.xml在某种程度上被某些服务或某些东西所触动) )。
What happened in our case was that like you, we have a single instance of an object that's defined as a static variable of some class, and just like you, it's initialized by a servlet that has it's load-on-startup parameter set. When WebLogic thinks there's a change, it reloads the webapp by garbage collecting the classloader (which is fine) but it doesn't re-initialize all the servlets that are marked "load-on-startup" (in our case, and I'm guessing yours, the servlet serves no purpose other than to initialize the static variable, there are no mappings to it, and so it cannot be invoke, the static variable gets GCed, but not-reinitialized, and the server needs to be restarted.
在我们的例子中发生的事情是,像你一样,我们有一个对象的单个实例被定义为某个类的静态变量,就像你一样,它由一个具有它的load-on-startup参数集的servlet初始化。当WebLogic认为存在变化时,它会通过垃圾收集类加载器来重新加载webapp(这很好),但它不会重新初始化所有标记为“load-on-startup”的servlet(在我们的例子中,我是'猜测你的,除了初始化静态变量之外没有任何目的,没有映射到它,因此无法调用,静态变量得到GCed,但没有重新初始化,服务器需要重新启动。
In our case, our solution was to initialize the static variable in a static initializer. The original developer used a servlet to initialize the variable because he wanted some servlet context information, which really wasn't necessary. If you need context information, you could try doing your initialization in a ServletContextListener.
在我们的例子中,我们的解决方案是在静态初始化程序中初始化静态变量。原始开发人员使用servlet来初始化变量,因为他想要一些servlet上下文信息,这实际上并不是必需的。如果需要上下文信息,可以尝试在ServletContextListener中进行初始化。
#2
Since the JMSFactory has a reference to them why would the gc destroy them?
既然JMSFactory引用了它们,为什么gc会破坏它们呢?
Well, are any objects still holding reference to the JMSFactory at this point?
那么,此时仍有任何对象仍然引用JMSFactory吗?
Typical singleton pattern keeps the reference to the singleton object in a static member:
典型的单例模式保持对静态成员中单例对象的引用:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
//constructor...
}
public static Singleton getInstance() { return instance; }
}
Is this not the pattern you are following? It is not possible to tell from the code you provided in your post, as you left out the actual singleton code...
这不是你所遵循的模式吗?从您在帖子中提供的代码中无法判断,因为您遗漏了实际的单例代码...
(BTW, using Singletons for something like this sounds like it would cause pains, besides being hard to test. See Singletons Are Pathlogical Liars)
(顺便说一句,使用Singletons这样的事情听起来会引起痛苦,除了难以测试之外。参见Singletons Are Pathlogical Liars)
#3
Without having all of the code this a tough question to solve. But there are tools to help out.
没有所有的代码这是一个难以解决的问题。但是有一些工具可以提供帮助。
Try this link: http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ It provides information about using jhat and jmap. Although the article is written to find memory leaks, it provides info on how to keep track of references to an object. Maybe you can track down why your references are disappearing.
试试这个链接:http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/它提供了有关使用jhat和jmap的信息。虽然本文是为了查找内存泄漏而编写的,但它提供了有关如何跟踪对象引用的信息。也许你可以找出你的参考文献消失的原因。
#4
You said the Sessions in the _sessions map were not being GC'd, but the JMSObjects were not. I doubt it's because it is something you wrote. It sounds like either the JMSFactory itself is being collected (i.e. singleton not implemented properly) or something is removing the keys from the maps. In either case, the JMSObjects would be eligible for GC, but the session objects would not because the list still has a reference to them.
你说_sessions映射中的Sessions不是GC,但是JMSObjects不是。我怀疑是因为这是你写的东西。听起来好像正在收集JMSFactory本身(即单例未正确实现)或者正在从地图中删除键。在任何一种情况下,JMSObjects都有资格使用GC,但会话对象不会,因为列表仍然有对它们的引用。
#5
Any chance that the classloader that loaded the JMSFactory was being unloaded, causing the JMSFactory class to be GC'ed (including the singleton instance), which frees up the HashMaps and their contents?
是否有机会卸载加载JMSFactory的类加载器,导致JMSFactory类被GC(包括单例实例),从而释放HashMaps及其内容?
#1
I think I know what your problem is, it's something I ran into a while back (on WebLogic 6). I believe it has to do with WebLogic's dynamic class reloading, which WebLogic seems to do from time to time, even when you're not in a development environment (I'm guessing the web.xml is somehow getting touched by some service or something).
我想我知道你的问题是什么,这是我在一段时间后遇到的事情(在WebLogic 6上)。我相信它与WebLogic的动态类重新加载有关,WebLogic似乎不时会这样做,即使你不在开发环境中(我猜测web.xml在某种程度上被某些服务或某些东西所触动) )。
What happened in our case was that like you, we have a single instance of an object that's defined as a static variable of some class, and just like you, it's initialized by a servlet that has it's load-on-startup parameter set. When WebLogic thinks there's a change, it reloads the webapp by garbage collecting the classloader (which is fine) but it doesn't re-initialize all the servlets that are marked "load-on-startup" (in our case, and I'm guessing yours, the servlet serves no purpose other than to initialize the static variable, there are no mappings to it, and so it cannot be invoke, the static variable gets GCed, but not-reinitialized, and the server needs to be restarted.
在我们的例子中发生的事情是,像你一样,我们有一个对象的单个实例被定义为某个类的静态变量,就像你一样,它由一个具有它的load-on-startup参数集的servlet初始化。当WebLogic认为存在变化时,它会通过垃圾收集类加载器来重新加载webapp(这很好),但它不会重新初始化所有标记为“load-on-startup”的servlet(在我们的例子中,我是'猜测你的,除了初始化静态变量之外没有任何目的,没有映射到它,因此无法调用,静态变量得到GCed,但没有重新初始化,服务器需要重新启动。
In our case, our solution was to initialize the static variable in a static initializer. The original developer used a servlet to initialize the variable because he wanted some servlet context information, which really wasn't necessary. If you need context information, you could try doing your initialization in a ServletContextListener.
在我们的例子中,我们的解决方案是在静态初始化程序中初始化静态变量。原始开发人员使用servlet来初始化变量,因为他想要一些servlet上下文信息,这实际上并不是必需的。如果需要上下文信息,可以尝试在ServletContextListener中进行初始化。
#2
Since the JMSFactory has a reference to them why would the gc destroy them?
既然JMSFactory引用了它们,为什么gc会破坏它们呢?
Well, are any objects still holding reference to the JMSFactory at this point?
那么,此时仍有任何对象仍然引用JMSFactory吗?
Typical singleton pattern keeps the reference to the singleton object in a static member:
典型的单例模式保持对静态成员中单例对象的引用:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
//constructor...
}
public static Singleton getInstance() { return instance; }
}
Is this not the pattern you are following? It is not possible to tell from the code you provided in your post, as you left out the actual singleton code...
这不是你所遵循的模式吗?从您在帖子中提供的代码中无法判断,因为您遗漏了实际的单例代码...
(BTW, using Singletons for something like this sounds like it would cause pains, besides being hard to test. See Singletons Are Pathlogical Liars)
(顺便说一句,使用Singletons这样的事情听起来会引起痛苦,除了难以测试之外。参见Singletons Are Pathlogical Liars)
#3
Without having all of the code this a tough question to solve. But there are tools to help out.
没有所有的代码这是一个难以解决的问题。但是有一些工具可以提供帮助。
Try this link: http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ It provides information about using jhat and jmap. Although the article is written to find memory leaks, it provides info on how to keep track of references to an object. Maybe you can track down why your references are disappearing.
试试这个链接:http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/它提供了有关使用jhat和jmap的信息。虽然本文是为了查找内存泄漏而编写的,但它提供了有关如何跟踪对象引用的信息。也许你可以找出你的参考文献消失的原因。
#4
You said the Sessions in the _sessions map were not being GC'd, but the JMSObjects were not. I doubt it's because it is something you wrote. It sounds like either the JMSFactory itself is being collected (i.e. singleton not implemented properly) or something is removing the keys from the maps. In either case, the JMSObjects would be eligible for GC, but the session objects would not because the list still has a reference to them.
你说_sessions映射中的Sessions不是GC,但是JMSObjects不是。我怀疑是因为这是你写的东西。听起来好像正在收集JMSFactory本身(即单例未正确实现)或者正在从地图中删除键。在任何一种情况下,JMSObjects都有资格使用GC,但会话对象不会,因为列表仍然有对它们的引用。
#5
Any chance that the classloader that loaded the JMSFactory was being unloaded, causing the JMSFactory class to be GC'ed (including the singleton instance), which frees up the HashMaps and their contents?
是否有机会卸载加载JMSFactory的类加载器,导致JMSFactory类被GC(包括单例实例),从而释放HashMaps及其内容?