Existe-t-il un moyen d’éviter les memory leaks de déploiement dans Tomcat?

Cette question s’adresse à toute personne ayant déjà testé le bouton “Rechercher des fuites” dans le gestionnaire Tomcat et obtenu des résultats comme ceux-ci:

Les applications Web suivantes ont été arrêtées (rechargées, non déployées), mais leurs classes des exécutions précédentes sont toujours chargées en mémoire, provoquant ainsi une fuite de mémoire (utilisez un profileur pour confirmer):
/ leaky-app-name

Je suppose que cela a quelque chose à voir avec cette erreur “Perm Gen Space” que vous obtenez souvent avec des redéploiements fréquents.

Donc, ce que je vois dans jconsole quand je déploie, c’est que mes classes chargées vont d’environ 2k à 5k. Ensuite, vous penseriez qu’un déploiement non déployé devrait les ramener à 2k mais ils restnt à 5k.

J’ai également essayé d’utiliser les options JVM suivantes:

-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled

J’ai vu des creux très mineurs dans la quantité d’espace Perm Gen utilisée, mais pas ce à quoi je m’attendais et le nombre de classes chargées n’a pas baissé.

Existe-t-il un moyen de configurer Tomcat ou de concevoir votre application pour mieux la décharger lors d’un déploiement? Ou sums-nous coincés avec le redémarrage du serveur après quelques sessions de débogage importantes?

Sortie de la version Tomcat:

Version du serveur: Apache Tomcat / 6.0.29
Serveur construit: 19 juillet 2010 1458
Numéro de serveur: 6.0.0.29
Nom du système d’exploitation: Windows 7
Version du système d’exploitation: 6.1
Architecture: x86
Version JVM: 1.6.0_18-b07
Fournisseur JVM: Sun Microsystems Inc.

Mettre à jour:

Grâce à la réponse de celias, j’ai décidé de faire un peu plus de recherches et je pense avoir trouvé le coupable dans mon application grâce à CXF, Spring et JAXB.

Après avoir appris à profiler une application Java, j’ai orienté le profileur sur Tomcat et pris quelques clichés et instantanés de tas pour voir à quoi ressemblaient les objects et les classes en mémoire. J’ai découvert que certaines des énumérations de mon schéma XML utilisées dans mes classes générées par CXF / JAXB (wsdl2java) persistaient après un non-déploiement. D’après mon vidage de tas, il semble que les objects étaient liés à une carte. Disclaimer: J’avoue que je suis encore un peu vert avec le profilage et le traçage de l’arbre d’appel d’un object peut être difficile en Java.

Je dois également mentionner que je n’ai même pas invoqué le service, juste déployé puis non déployé. Les objects eux-mêmes semblaient être chargés via une reflection initiée à partir du spring lors du déploiement. Je crois que j’ai suivi la convention pour la mise en place d’un service CXF au spring. Donc, je ne suis pas sûr à 100% s’il s’agit de Spring / CXF, JAXB ou de défaut de reflection.

En guise de remarque: l’application en question est un service Web utilisant Spring / CXF et le XML se trouve être un schéma assez complexe (une extension de NIEM ).

Si vous voulez vous assurer de ne pas provoquer de fuite, procédez comme suit:

  • Assurez-vous que votre application Web n’utilise pas de classes Java situées dans les bibliothèques partagées du conteneur Web. Si vous avez des bibliothèques partagées, assurez-vous qu’il n’y a pas de références fortes aux objects dans ces bibliothèques
  • Évitez d’utiliser des variables statiques, en particulier sur les objects Java tels que HashTable, Sets, etc. Si nécessaire, assurez-vous d’appeler remove pour libérer les objects avec les maps, les listes …

Voici également un bon article sur ThreadLocal et MemoryLeaks – http://blog.arendsen.net/index.php/2005/02/22/threadlocals-and-memory-leaks-revisited/

Tomcat 7 est censé apporter des améliorations dans ce domaine. Voir Fonctionnalités d’Apache Tomcat 7 , section intitulée Plus de fuites!

Ils pensent pouvoir faire face à de nombreuses memory leaks causées par les applications Web. Malheureusement, il est toujours en version bêta.

En dehors de cela, je peux juste dire que j’ai fait la même expérience et que je n’ai pas trouvé de solution. Le déploiement nécessite généralement le redémarrage de Tomcat. Je n’ai aucune idée de qui est le coupable: mon application Web, Tomcat, Hibernate, Tapestry ou plusieurs d’entre eux.