Question Traiter l'erreur "java.lang.OutOfMemoryError: PermGen space"


Récemment, j'ai rencontré cette erreur dans mon application Web:

java.lang.OutOfMemoryError: espace PermGen

C'est une application Hibernate / JPA + IceFaces / JSF typique fonctionnant sur Tomcat 6 et JDK 1.6. Apparemment, cela peut se produire après le redéploiement d'une application plusieurs fois.

Quelles sont les causes et que peut-on faire pour l'éviter? Comment puis-je résoudre le problème?


1178
2017-09-18 03:29


origine


Réponses:


La solution consistait à ajouter ces indicateurs à la ligne de commande JVM lorsque Tomcat est démarré:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Vous pouvez le faire en fermant le service tomcat, puis en accédant au répertoire Tomcat / bin et en exécutant tomcat6w.exe. Sous l'onglet "Java", ajoutez les arguments à la boîte "Options Java". Cliquez sur "OK", puis redémarrez le service.

Si vous obtenez une erreur le service spécifié n'existe pas en tant que service installé vous devriez courir:

tomcat6w //ES//servicename

Nom du service est le nom du serveur vu dans services.msc

Source: Commentaire de orx sur Les réponses agiles d'Eric.


549
2017-09-17 22:23



Tu ferais mieux d'essayer -XX:MaxPermSize=128M plutôt que -XX:MaxPermGen=128M.

Je ne peux pas dire l'utilisation précise de ce pool de mémoire, mais cela a à voir avec le nombre de classes chargées dans la JVM. (Ainsi, l'activation du déchargement de classe pour tomcat peut résoudre le problème.) Si vos applications génèrent et compilent des classes en cours d'exécution, il est plus probable qu'elles aient besoin d'un pool de mémoire plus grand que celui par défaut.


247
2017-09-18 02:09



Les erreurs PermGen du serveur d'applications qui se produisent après plusieurs déploiements sont probablement causées par les références contenues dans le conteneur dans les chargeurs de classe de vos anciennes applications. Par exemple, l'utilisation d'une classe de niveau de journalisation personnalisée entraîne le maintien des références par le chargeur de classes du serveur d'applications. Vous pouvez détecter ces fuites inter-classeur en utilisant des outils d'analyse JVM (JDK6 +) modernes tels que jmap et jhat pour voir quelles classes sont conservées dans votre application et en redessinant ou en supprimant leur utilisation. Les suspects habituels sont des bases de données, des enregistreurs et d'autres bibliothèques au niveau du framework de base.

Voir Classloader fuit: l'exception redoutée "java.lang.OutOfMemoryError: PermGen space", et surtout son poste de suivi.


152
2018-03-11 22:24



Les erreurs courantes que les gens font sont de penser que l'espace tas et l'espace permgen sont les mêmes, ce qui n'est pas du tout vrai. Vous pourriez avoir beaucoup d'espace restant dans le tas, mais peut toujours manquer de mémoire dans permgen.

Les causes communes de OutofMemory dans PermGen sont ClassLoader. Chaque fois qu'une classe est chargée dans JVM, toutes ses méta-données, ainsi que Classloader, sont conservées dans la zone PermGen et elles seront collectées lorsque le Classloader qui les a chargées est prêt pour la récupération de place. Dans Case Classer a une fuite de mémoire que toutes les classes chargées par elle restera en mémoire et provoquera une mémoire de permGen une fois que vous le répétez plusieurs fois. L'exemple classique est Java.lang.OutOfMemoryError: espace PermGen dans Tomcat.

Maintenant, il y a deux façons de résoudre ceci:
1. Trouvez la cause de la fuite de mémoire ou s'il y a une fuite de mémoire.
2. Augmenter la taille de l'espace PermGen en utilisant le paramètre JVM -XX:MaxPermSize et -XX:PermSize.

Vous pouvez également vérifier 2 Solution de Java.lang.OutOfMemoryError en Java pour plus de détails.


65



Utilisez le paramètre de ligne de commande -XX:MaxPermSize=128m pour une JVM Sun (en substituant évidemment 128 pour la taille dont vous avez besoin).


39



Essayer -XX:MaxPermSize=256m et si cela persiste, essayez -XX:MaxPermSize=512m


35



je ajoutée  -XX: MaxPermSize = 128m (vous pouvez expérimenter ce qui fonctionne le mieux) pour Arguments VM comme j'utilise eclipse ide. Dans la plupart des JVM, par défaut PermSize est d'environ 64 Mo qui manque de mémoire s'il y a trop de classes ou un grand nombre de chaînes dans le projet.

Pour éclipse, il est également décrit à répondre.

ÉTAPE 1 : Double cliquez sur le serveur Tomcat à Les serveurs Languette

enter image description here

ÉTAPE 2 : Lancer le lancement Conf et ajouter -XX: MaxPermSize = 128m à la fin de existant Arguments VM.

enter image description here


24



Je me suis efforcé de résoudre ce problème en déployant et en annulant le déploiement d'une application Web complexe, et j'ai pensé ajouter une explication et ma solution.

Lorsque je déploie une application sur Apache Tomcat, un nouveau ClassLoader est créé pour cette application. Le ClassLoader est ensuite utilisé pour charger toutes les classes de l'application, et à undeploy, tout est supposé s'en aller bien. Cependant, en réalité ce n'est pas aussi simple.

Une ou plusieurs classes créées au cours de la vie de l'application Web contiennent une référence statique qui, quelque part le long de la ligne, fait référence au ClassLoader. Comme la référence est à l'origine statique, aucune quantité de collecte des ordures ne nettoiera cette référence - le ClassLoader, et toutes les classes qu'il charge, sont là pour rester.

Et après quelques redéploiements, nous rencontrons l'OutOfMemoryError.

Maintenant, c'est devenu un problème assez sérieux. Je peux m'assurer que Tomcat est redémarré après chaque redéploiement, mais cela annule l'ensemble du serveur, et pas seulement l'application en cours de redéploiement, ce qui est souvent impossible.

J'ai donc mis au point une solution dans le code, qui fonctionne sur Apache Tomcat 6.0. Je n'ai pas testé sur d'autres serveurs d'applications, et je dois souligner que il est très probable que cela ne fonctionnera pas sans modification sur un autre serveur d'application.

Je voudrais aussi dire que personnellement je déteste ce code, et que personne ne devrait utiliser cela comme une "solution miracle" si le code existant peut être modifié pour utiliser des méthodes d'arrêt et de nettoyage correctes. La seule fois où cela devrait être utilisé est s'il y a une bibliothèque externe dont votre code dépend (dans mon cas, c'était un client RADIUS) qui ne fournit pas un moyen de nettoyer ses propres références statiques.

Quoi qu'il en soit, avec le code. Cela doit être appelé au point où l'application est en cours de désinstallation, comme la méthode destroy d'une servlet ou (la meilleure approche) la méthode contextDestroyed de ServletContextListener.

//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
    try {
        classLoaderClassesField = clazz.getDeclaredField("classes");
    } catch (Exception exception) {
        //do nothing
    }
    clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);

List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));

for (Object o : classes) {
    Class c = (Class)o;
    //Make sure you identify only the packages that are holding references to the classloader.
    //Allowing this code to clear all static references will result in all sorts
    //of horrible things (like java segfaulting).
    if (c.getName().startsWith("com.whatever")) {
        //Kill any static references within all these classes.
        for (Field f : c.getDeclaredFields()) {
            if (Modifier.isStatic(f.getModifiers())
                    && !Modifier.isFinal(f.getModifiers())
                    && !f.getType().isPrimitive()) {
                try {
                    f.setAccessible(true);
                    f.set(null, null);
                } catch (Exception exception) {
                    //Log the exception
                }
            }
        }
    }
}

classes.clear();

22



Alternativement, vous pouvez passer à JRockit qui gère permgen différemment puis jvm du soleil. Il a généralement de meilleures performances aussi bien.

http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html


15



1) Augmenter la taille de la mémoire PermGen

La première chose que l'on peut faire est de faire en sorte que la taille de l'espace de tas de la génération permanente soit plus grande. Cela ne peut pas être fait avec les arguments JVM habituels -Xms (taille initiale du tas) et -Xmx (taille maximum du tas), puisque comme mentionné, l'espace de génération de tas permanent est entièrement séparé de l'espace Java Heap normal, et ces arguments définissent l'espace pour cet espace de tas Java normal. Cependant, il existe des arguments similaires qui peuvent être utilisés (au moins avec Sun / OpenJDK jvms) pour augmenter la taille du tas de génération permanente:

 -XX:MaxPermSize=128m

La valeur par défaut est 64m.

2) Activer le balayage

Une autre façon d'en prendre soin est de permettre le déchargement des classes pour que votre PermGen ne soit jamais épuisé:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Des trucs comme ça ont fonctionné de la magie pour moi dans le passé. Une chose cependant, il y a un compromis significatif dans l'utilisation de ceux-ci, puisque les balayages de permgen feront comme 2 demandes supplémentaires pour chaque demande que vous faites ou quelque chose dans ce sens. Vous devrez équilibrer votre utilisation avec les compromis.

Vous pouvez trouver les détails de cette erreur.

http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html


14



J'ai eu le problème dont nous parlons ici, mon scénario est eclipse-helios + tomcat + jsf et ce que vous faisiez est de faire un déploiement d'une application simple pour tomcat. Je montrais le même problème ici, résolu comme suit.

En éclipse, allez à les serveurs onglet double-cliquez sur le serveur enregistré dans mon cas tomcat 7.0, il ouvre mon serveur de fichiers Informations générales d'inscription. Sur la section "Informations générales" Clique sur le lien "Configuration de lancement ouverte" , cela ouvre l'exécution des options du serveur dans l'onglet Arguments dans les arguments VM ajoutés à la fin de ces deux entrées

-XX: MaxPermSize = 512m
-XX: PermSize = 512m

et prêt.


13