2009-07-14 4 views
1

Mes développeurs et moi avons un problème avec les objets qui sont collectés dans notre application quand nous ne voulons pas qu'ils le soient. Nous utilisons Java avec Weblogic 10g3. Nous programmons un modèle singleton pour gérer toutes nos connexions JMS.Pourquoi cela est-il collecté

Il y a deux classes concernées:

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 
} 

La méthode d'initialisation des servlets appelle la méthode singlton JMSFactory, toutes les nouvelles sessions sont placées dans les _sessions hashmap et nouveaux MessageConsumer/MessageProducers sont créés comme JMSObject et placé dans le hash_jmsobjects, dans la liste appropriée. Le problème est que lorsque le système est en cours d'exécution, les JMSObjects de la liste récupèrent les ordures après un certain temps (parfois 5 minutes plus tard, après quelques heures). Nous avons regardé cela pendant quelques jours mais nous n'avons trouvé aucun raison pour laquelle les JMSObjects sont collectés. Puisque le JMSFactory a une référence à eux, pourquoi le gc les détruirait-il?

En fin de compte nous avons fixé en changeant les classes comme suit (sans changer les interfaces de méthode):

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 
} 

Jusqu'à présent, pour tester les JMSObjects ne sont pas gc'ed. Il a fonctionné pendant 2 jours. Est-ce que quelqu'un peut expliquer pourquoi la référence indirecte provoque l'exécution de la commande JMSObject? Et pourquoi les Sessions dans le _sessions Hashmap n'etaient pas gc'ed? Cela a-t-il quelque chose à voir avec le fait que les Sessions sont construites dans des types Javax et que JMSObject est quelque chose que nous avons écrit?

+0

Quand le 'JMSObject's obtient des ordures rassemblées, je le prends la taille de la liste reste la même, mais vous obtenez' null's quand vous essayez et le lisez? –

+0

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

Répondre

2

Je pense que je connais votre problème, c'est quelque chose que j'ai rencontré il y a un moment (sur WebLogic 6). Je crois que cela a à voir avec le rechargement dynamique de classe de WebLogic, que WebLogic semble faire de temps en temps, même quand vous n'êtes pas dans un environnement de développement (je devine que le web.xml est en quelque sorte touché par un service ou quelque chose). Ce qui s'est passé dans notre cas, c'est que comme nous, nous avons une seule instance d'un objet défini comme une variable statique d'une classe, et tout comme vous, il est initialisé par une servlet qui a son chargement au démarrage jeu de paramètres. Lorsque WebLogic pense qu'il y a un changement, il recharge la webapp en récupérant le classloader (ce qui est bien) mais il ne réinitialise pas toutes les servlets marquées "load-on-startup" (dans notre cas, et Je suppose que le servlet ne sert à rien d'autre qu'à initialiser la variable statique, il n'y a pas de mappage, et donc il ne peut pas être invoqué, la variable statique est GCed, mais pas-réinitialisé, et le serveur doit être

Dans notre cas, notre solution consistait à initialiser la variable statique dans un initialiseur statique.Le développeur d'origine a utilisé une servlet pour initialiser la variable car il voulait des informations de contexte de servlet, ce qui n'était pas vraiment nécessaire. besoin d'informations contextuelles, vous pouvez essayer de faire votre initialisation dans un ServletContextListener

+0

@Jack Leow; intéressant, nous devrons nous pencher sur le comportement du Dynamic Class Reloading. On dirait que vous dites que ce n'est pas juste. Nous ne voyons pas le problème avec la mise en œuvre plus récente (deuxième bloc de code), mais encore besoin de comprendre quelle était la cause première. Merci. – beggs

+1

Je vois cela, et c'est l'une des raisons pour lesquelles je n'ai pas répondu plus tôt. Cela dit, vous avez dit que cela n'était stable que depuis quelques jours, et dans notre cas, notre système peut parfois durer des semaines avant d'afficher ce comportement (ce qui rend le dépannage très amusant). –

+0

Je suppose que cela a été accepté parce que la deuxième version a commencé à montrer des problèmes? :) –

5

Puisque le JMSFactory a une référence à eux pourquoi le gc les détruirait-il?

Eh bien, y a-t-il encore des objets contenant des références à JMSFactory à ce stade?

singleton typique conserve la référence à l'objet singleton dans un membre statique:

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

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

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

est-ce pas le modèle que vous suivez? Il n'est pas possible de dire à partir du code que vous avez fourni dans votre message, car vous avez omis le code singleton réel ...

(BTW, en utilisant Singletons pour quelque chose comme ça sonne comme ça causerait des douleurs, en plus d'être difficile à voir Singletons Are Pathlogical Liars)

+0

@matt b ... oui les choses sont statiques, un code légèrement différent (nous instancions le singleton dans le constructeur, mais la variable est statique). link – beggs

+0

Eh bien, c'est un peu difficile de vous aider à résoudre votre problème si le code que vous publiez n'est pas vraiment le code qui a des problèmes ... –

+0

Impossible de publier le code commercial ... ;-) viole règles d'entreprise. – beggs

0

Vous avez dit que les sessions de la carte _sessions n'étaient pas en cours de GC'd, mais que les objets JMSO ne l'étaient pas. Je doute que ce soit parce que c'est quelque chose que tu as écrit. Il semble que soit le JMSFactory lui-même est collecté (c'est-à-dire que singleton n'est pas implémenté correctement) soit quelque chose supprime les clés des cartes. Dans les deux cas, les JMSObjects seraient éligibles pour GC, mais les objets de session ne le seraient pas car la liste contient toujours une référence.

1

Sans avoir tout le code, c'est une question difficile à résoudre. Mais il y a des outils pour aider.

Essayez ce lien: http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ Il fournit des informations sur l'utilisation de jhat et jmap. Bien que l'article soit écrit pour trouver des fuites de mémoire, il fournit des informations sur la façon de garder une trace des références à un objet. Peut-être que vous pouvez découvrir pourquoi vos références disparaissent.

0

Y a-t-il une chance que le chargeur de classe qui a chargé JMSFactory ait été déchargé, ce qui a provoqué la GC de la classe JMSFactory (y compris l'instance singleton), ce qui libère les HashMaps et leur contenu?

Questions connexes