2009-07-14 15 views
1

Meine Entwickler und ich haben ein Problem mit Objekten, die in unserer Anwendung als Müll gesammelt werden, wenn wir sie nicht haben wollen. Wir verwenden Java mit Weblogic 10g3. Wir programmieren ein Singleton-Muster, um alle unsere JMS-Verbindungen zu handhaben.Warum wird dieser Müll gesammelt?

Es gibt zwei Klassen beteiligt: ​​

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 
} 

Die init-Methode der Servlets ruft die JMSFactory singlton Methode, alle neuen Sitzungen werden in den _sessions platziert HashMap und neue Message/MessageProducers werden als JMSObject erstellt und platziert in der _jmsobjects-Hashmap in der entsprechenden Liste.

Das Problem ist, dass wenn das System läuft die JMSObjects in der Liste Müll nach einiger Zeit (manchmal in 5 Minuten andere Zeiten nach ein paar Stunden) Grund dafür, dass die JMSObjects gesammelt werden. Da die JMSFactory einen Verweis auf sie hat, warum würde der GC sie zerstören?

Am Ende haben wir es durch eine Änderung der Klassen wie folgt festgelegt (ohne Schnittstellen-Methode zu ändern):

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 
} 

Bisher ist die JMSObjects bei der Prüfung nicht gc'ed werden. Es läuft seit 2 Tagen.

Kann jemand erklären, warum der indirekte Verweis das JMSObject veranlasst, gc'ed zu werden? Und warum wurden die Sessions in der _sessions Hashmap nicht gc'ed? Hat es etwas damit zu tun, dass die Sessions in Javax-Typen eingebaut sind und das JMSObject etwas ist, was wir geschrieben haben?

+0

Wenn die 'JMSObject's Müll gesammelt werden, nehme ich es die Größe der Liste bleibt gleich, aber Sie erhalten' null ', wenn Sie versuchen, es zu lesen? –

+0

@Jack Leow, Ja NullPointerException ... :-( – beggs

Antwort

2

Ich denke, ich weiß, was Ihr Problem ist, es ist etwas, in das ich vor einer Weile lief (auf WebLogic 6). Ich glaube, dass es mit dem dynamischen Klassenladen von WebLogic zu tun hat, was WebLogic von Zeit zu Zeit zu tun scheint, auch wenn Sie nicht in einer Entwicklungsumgebung sind (ich nehme an, dass die web.xml irgendwie von einem Dienst oder etwas berührt wird)). In unserem Fall ist es passiert, dass wir wie Sie eine einzelne Instanz eines Objekts haben, das als statische Variable einer Klasse definiert ist. Genau wie Sie wird es von einem Servlet initialisiert, das beim Start geladen wird Parametersatz. Wenn WebLogic denkt, dass es eine Änderung gibt, lädt es die WebApp erneut, indem es den Classloader sammelt (was in Ordnung ist) , aber Es initialisiert nicht alle Servlets, die als "load-on-startup" gekennzeichnet sind (in unserem Fall und Ich schätze Ihr, das Servlet dient nur der Initialisierung der statischen Variablen, es gibt keine Zuordnungen dazu und daher kann es nicht aufgerufen werden, die statische Variable wird GCed, aber nicht reinitialisiert, und der Server muss es sein neu gestartet

In unserem Fall bestand unsere Lösung darin, die statische Variable in einem statischen Initialisierer zu initialisieren.Der ursprüngliche Entwickler verwendete ein Servlet, um die Variable zu initialisieren, weil er einige Servletkontextinformationen benötigte, was wirklich nicht notwendig war Wenn Sie Kontextinformationen benötigen, können Sie versuchen, Ihre Initialisierung in einer ServletContextListener.

+0

@Jack Leow; interessant, wir müssen uns das Verhalten des Dynamic Class Reloading ansehen. Klingt so, als ob du sagst, dass es nicht fair spielt. Wir sehen das Problem mit der neueren Implementierung (zweiter Codeblock) nicht, müssen aber noch herausfinden, was die Ursache war. Vielen Dank. – beggs

+1

Ich sehe das, und das ist einer der Gründe, warum ich nicht früher reagiert habe. Das heißt, du hast gesagt, dass es nur für ein paar Tage stabil ist, und in unserem Fall kann unser System manchmal Wochen lang gehen, bevor es dieses Verhalten zeigt (es macht viel Spaß, Fehler zu beheben). –

+0

Ich nehme an, das wurde akzeptiert, weil die zweite Version Probleme zeigte? :) –

5

Da die JMSFactory einen Verweis auf sie hat, warum würde der GC sie zerstören?

Nun, sind irgendwelche Objekte immer noch Bezug auf die JMSFactory zu diesem Zeitpunkt?

Typische Singletonmuster hält den Verweis auf das Singleton-Objekt in einem statischen Element:

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

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

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

Ist das nicht das Muster, das Sie folgen? Es ist nicht möglich, aus dem Code, den Sie in Ihrem Beitrag angegeben, zu unterscheiden, da Sie den tatsächlichen Singleton-Code weggelassen haben ...

(BTW, mit Singletons für etwas wie das klingt, als würde es Schmerzen verursachen, neben schwer zu sein Siehe Singletons Are Pathlogical Liars)

+0

@matt b ... ja Dinge sind statisch, etwas anderer Code (wir instanziieren den Singleton im Konstruktor, aber die Variable ist statisch). Interessanter Artikel, danke für die link – beggs

+0

Nun, es ist ein wenig schwer, Ihnen zu helfen, Ihr Problem zu lösen, wenn der Code, den Sie veröffentlichen, nicht wirklich der Code ist, der Probleme hat ... –

+0

Kann den Handelscode wirklich nicht posten ... ;-) verletzt Unternehmensregeln. – beggs

0

Sie sagten, dass die Sessions in der _sessions-Map nicht gecodiert wurden, aber die JMSObjects nicht. Ich bezweifle, dass es daran liegt, dass du etwas geschrieben hast. Es hört sich so an, als würde entweder die JMSFactory selbst gesammelt werden (d. H. Singleton nicht korrekt implementiert) oder etwas entfernt die Schlüssel von den Maps. In beiden Fällen wären die JMSObjects für GC geeignet, die Sitzungsobjekte jedoch nicht, da die Liste immer noch einen Verweis auf sie enthält.

1

Ohne all den Code ist dies eine schwierige Frage zu lösen. Aber es gibt Tools, die helfen können.

Versuchen Sie diesen Link: http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ Es bietet Informationen zur Verwendung von Jhat und Jmap. Obwohl der Artikel geschrieben wurde, um Speicherlecks zu finden, enthält er Informationen darüber, wie Verweise auf ein Objekt verfolgt werden können. Vielleicht können Sie herausfinden, warum Ihre Referenzen verschwinden.

0

Jede Möglichkeit, dass der Klassenlader, der die JMSFactory geladen hat, entladen wurde, wodurch die JMSFactory-Klasse GC (einschließlich der Singleton-Instanz) wurde, was die HashMaps und deren Inhalt freigibt?

Verwandte Themen