web-dev-qa-db-fra.com

Existe-t-il un moyen d'éviter les fuites de mémoire de non-déploiement dans Tomcat?

Cette question s'adresse à tous ceux qui ont déjà testé le bouton "Rechercher des fuites" dans le gestionnaire Tomcat et ont obtenu des résultats comme celui-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 l'erreur "Perm Gen space" que vous obtenez souvent avec des redéploiements fréquents.

Donc, ce que je vois dans jconsole lorsque je déploie, c'est que mes classes chargées vont d'environ 2k à 5k. Ensuite, vous pensez qu'un retrait devrait les ramener à 2k mais ils restent à 5k.

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

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

J'ai vu des baisses TRÈS mineures 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 décharger lors d'un retrait? Ou sommes-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
Version du serveur: 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.

Mise à jour:

Grâce à la réponse de celias, j'ai décidé de creuser un peu plus et je pense avoir déterminé le coupable dans ma candidature grâce à CXF, Spring et JAXB.

Après avoir appris à profiler une application Java application, j'ai pointé le profileur vers Tomcat et pris quelques vidages de mémoire et des instantanés pour voir à quoi ressemblaient les objets et les classes en mémoire. J'ai découvert que certains des les énumérations de mon schéma XML utilisé dans mes classes générées par CXF/JAXB (wsdl2Java) persistaient après un retrait de déploiement. D'après mon vidage de tas, il semble que les objets étaient liés à une carte. le profilage et le traçage de l'arborescence d'appels d'un objet peuvent être difficiles en Java.

Je dois également mentionner que je n'ai même pas appelé le service, je l'ai simplement déployé puis non déployé. Les objets eux-mêmes semblaient être chargés via une réflexion initiée à partir du printemps lors du déploiement. Je crois que j'ai suivi la convention pour la mise en place d'un service CXF au printemps. Je ne suis donc pas sûr à 100% s'il s'agit de Spring/CXF, JAXB ou de la faute de réflexion.

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

54
waltwood

Si vous voulez vous assurer de ne pas provoquer de fuites, vous devez procéder comme suit:

  • Assurez-vous que votre application Web n'utilise aucune classe Java qui se trouve 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 objets dans ces bibliothèques
  • Évitez d'utiliser des variables statiques, en particulier sur Java objets comme HashTable, Sets, etc. Si vous en avez besoin, assurez-vous d'appeler remove pour libérer les objets avec les cartes, 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/

15
celias

Tomcat 7 est censé apporter des améliorations dans ce domaine. Voir Fonctionnalités d'Apache Tomcat 7 , section intitulée No More Leaks!

Ils pensent qu'ils peuvent désormais faire face à de nombreuses fuites de mémoire causées par les applications Web. Malheureusement, il est toujours en version bêta.

A part ça, 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 de redémarrer Tomcat par la suite. Je n'ai aucune idée de qui est le coupable: mon application web, Tomcat, Hibernate, Tapestry ou plusieurs d'entre eux.

6
Codo