web-dev-qa-db-fra.com

JBoss 7, Java.lang.OutOfMemoryError: espace PermGen

J'ai frappé cette erreur où l'utilisation du processeur atteint ses limites et JBoss a besoin d'un redémarrage (Java.lang.OutOfMemoryError: PermGen space). 

J'ai trouvé une solution pour l'ancienne version de JBoss afin d'augmenter la MaxPermSize. Je suppose que la même chose vaut pour JBoss7.

Quelle valeur serait suffisante pour ne plus avoir de problème? Existe-t-il un moyen d’éviter définitivement ce problème (par exemple, utilisez un VM différent de JRockit)?

25
MaVRoSCy

Comme cela se produit après plusieurs redéploiements, il semble que vous ayez rencontré une fuite de chargeur de classe , un type courant de fuite permgen .

Ces jolies bêtes se produisent à cause de références normales (non faibles) d'objets appartenant au conteneur à des objets qui sont des instances de classes chargées à partir du chargeur de classes de l'application. Si ces références ne sont pas effacées lors de l'annulation du déploiement, il existe encore une chaîne de références solide vers le chargeur de classes de l'application. Il ne peut donc pas s'agir d'une commande GC et les classes chargées ne peuvent pas être libérées.

Les collections statiques dans les classes de conteneur auxquelles des références non statiques aux classes d'application ont été ajoutées sont une cause courante.

JBoss AS 7 contient des dispositions assez strictes dans son système de modules pour éviter les fuites de chargeur de classe. Je suis donc surpris que vous ayez réussi à en déclencher un. Je n'ai pas vu de fuite d'un chargeur de classe depuis que j'ai déménagé de Glassfish vers AS7.

Augmenter MaxPermSize vous fera gagner du temps, mais le problème ne sera pas résolu. 

Vous devez vraiment comprendre pourquoi le chargeur de classes fuit. Faire cela est "amusant". Vous aimez les taxes, les défauts intermittents et le nettoyage de la douche, n'est-ce pas? Consultez les liens dans la première partie de certains blogs qui vous aideront à détecter la fuite. Vous voudrez utiliser VisualVM et OQL pour numériser des références à votre chargeur de classe, ou effectuer un dump de tas et utiliser jhat (partie du JDK) pour trouver les références. Dans les deux cas, l’idée est de déterminer où se trouve la chaîne de références forte entre le serveur d’application et votre chargeur de classes via les instances de vos classes d’application.

Alternativement, il peut être utile de prendre une copie de votre application, puis d'extraire des fragments de celle-ci jusqu'à ce que la fuite disparaisse. Vous pouvez savoir s'il y a une fuite en connectant VisualVM ou une autre surveillance au serveur d'applications VM et en surveillant si PermGen augmente après au moins deux cycles de déploiement/annulation de déploiement. Envisagez d'automatiser les cycles de déploiement/annulation de déploiement. Limitez la cause de la fuite à une petite partie de votre application et/ou à l'une de ses dépendances et créez un petit cas de test autonome, puis soumettez-le sous forme de rapport de bogue sur (a) JBoss AS 7, car destiné à arrêter cela et (b) le coupable qui détient la référence.

Si vous limitez la cause à une dépendance intégrée à votre archive de déploiement, son déplacement dans un module JBoss AS 7 peut résoudre le problème. Créez un module JBoss pour ce dernier, déployez-le dans le répertoire modules de AS7 et ajoutez-lui une dépendance à votre déploiement via votre Manifest.MF ou un jboss-deployment-structure.xml. Voir le documentation sur le chargeur de classes AS7 .

C'est pourquoi le fait que le projet Jigsaw ait été différé me rend triste. Java a besoin d'un système de modules puissant qui élimine ce problème.

54
Craig Ringer

Le paramètre VM est:

-XX:MaxPermSize=256M

Faites juste assez grand pour que vous n'atteigniez pas la limite.

De manière générale, la mémoire permanente est utilisée pour les objets associés aux classes et aux chaînes internes. Vous ne devriez pas vous épuiser à moins d'utiliser beaucoup de classes différentes.

8
Bohemian

Nous avons dû faire exactement la même chose et, malheureusement, visualvm n'a pas fait grand chose pour nous.

Nous avons finalement utilisé Eclipse mat pour analyser le vidage de tas généré lors d'un crash, puis avons extrait le rapport leak suspects qui nous indiquait qu'un grand nombre d'instances ModuleClassLoader avaient été divulguées.

En cliquant sur l'une des instances dans l'onglet Vue d'ensemble, puis en sélectionnant merge shortest paths to GC roots + exclude weak references, nous nous sommes retrouvés avec le coupable qui ne permettait pas à ces instances ModuleClassLoader d'être gérées!

https://smalldata.tech/blog/2015/09/29/detecting-Java-permgen-memory-leak

4
Victor Parmar

Pourquoi ça arrive? 

L'erreur "PermGen" se produit lorsque la machine virtuelle Java est à court de mémoire dans la génération permanente. Rappelons que Java a un éboueur de génération, avec quatre générations: eden, jeune, vieux et permanent. Dans la génération eden, les objets sont très courts la vie et la collecte des ordures est rapide et souvent. La jeune génération se compose d’objets ayant survécu à la génération eden (ou a été poussé au stade jeune parce que la génération eden était pleine au moment de l’allocation ), le ramassage des ordures dans la jeune génération est inférieur à. fréquents mais qui se produisent encore à des intervalles assez réguliers (à condition que votre application fasse réellement quelque chose et alloue des objets tous les maintenant et ensuite). L'ancienne génération, eh bien, vous l'avez compris. Il contient objets qui ont survécu à la jeune génération ou qui ont été repoussés, et la collecte des ordures ménagères est encore moins rare mais peut encore se produire. Et enfin, la génération permanente. C'est pour les objets que le machine virtuelle a décidé de soutenir la vie éternelle - qui est précisément le cœur du problème. Objets de la génération permanente ne sont jamais ramassés; c'est-à-dire, dans des circonstances normales, lorsque jvm est démarré avec des paramètres de ligne de commande normaux. Et alors se produit lorsque vous redéployez votre application Web, c’est votre fichier WAR est décompressé et ses fichiers de classe chargés dans le jvm. Et voici le chose: finit presque toujours dans la génération permanente ... (pris de: http://rlogiacco.blogspot.com/2009/02/jboss-and-permgen-outofmemoryerror.html )

Voici quelques conseils: 

utilisez ces paramètres pour votre machine virtuelle Java. ils disent au garbage collector d'invoquer son algorithme également sur le PermGen.

set Java_OPTS=-Xms512m -Xmx1024m 
-XX:PermSize=512m 
-XX:MaxPermSize=1024m 
-XX:+UseConcMarkSweepGC 
-XX:+CMSPermGenSweepingEnabled 
-XX:+CMSClassUnloadingEnabled 
  • Le paramètre CMSPermGenSweepingEnabled inclut le PermGen dans une exécution Garbage. Par défaut, l’espace PermGen n’est jamais inclus dans la récupération de place (et croît donc sans limite).
  • Le paramètre CMSClassUnloadingEnabled indique au balayage PermGen garbage Collection de prendre des mesures sur les objets de classe. Par défaut, les objets de classe Bénéficient d'une exemption, même lorsque l'espace PermGen est en cours de visite Au cours d'une collection de garabage.

Redémarrez votre JBOSS car chaque fois que vous déployez une application, vous augmentez la quantité de données dans le PermGen. 

Vous pouvez également utiliser la machine virtuelle Java JRocket au lieu de la machine virtuelle Sun. il n'a pas de PermGen dans son algorithme Garbage Collector. 

1
Kamal SABBAR