Traitant de "la java.lang.OutOfMemoryError: erreur de PermGen space"

récemment, j'ai rencontré cette erreur dans mon application web:

de java.lang.OutOfMemoryError: PermGen space

c'est une application typique D'hibernation/JPA + IceFaces/JSF fonctionnant sur Tomcat 6 et JDK 1.6. Apparemment cela peut se produire après le redéploiement d'une demande un peu de temps.

Quelle en est la cause et ce qui peut être fait pour l'éviter? Comment puis-je résoudre le problème?

1190
demandé sur Chris 2008-09-18 02:13:48

30 réponses

la solution était d'ajouter ces drapeaux à la ligne de commande JVM lorsque Tomcat est lancé:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

vous pouvez faire cela en fermant le service tomcat, puis en allant dans le répertoire Tomcat/bin et en lançant tomcat6w.exe. Sous L'onglet" Java", ajoutez les arguments à la boîte" Java Options". Cliquez sur " OK " et redémarrez le service.

Si vous obtenez une erreur le service spécifié n'existe pas en tant que service installé vous devez exécuter:

tomcat6w //ES//servicename

nom de service est le nom du serveur tel qu'il est vu dans les services.msc

Source: commentaire d'orx sur Eric's Agile Answers .

550
répondu Chris 2013-10-29 15:44:25

Vous devriez 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 il a à voir avec le nombre de classes chargées dans la JVM. (Permettre ainsi le 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 le pool par défaut.

248
répondu 2 revs, 2 users 80%toesterdahl 2011-02-24 13:08:35
Les erreurs

PermGen sur le serveur D'applications qui se produisent après plusieurs déploiements sont probablement causées par des références contenues par le conteneur dans les classloaders de vos anciennes applications. Par exemple, en utilisant une classe de niveau de log personnalisée, les références seront conservées par classloader du serveur app. Vous pouvez détecter ces fuites inter-classloader en utilisant les outils d'analyse JVM modernes (JDK6+) tels que jmap et jhat pour voir quelles classes continuent d'être conservées dans votre application, et en redessinant ou en éliminant leur utilisation. Habituel les suspects sont des bases de données, des loggers, et d'autres bibliothèques de base-cadre de niveau.

Voir chargeur de classe de fuites: le redoutable "de java.lang.OutOfMemoryError: PermGen space "exception , et surtout son followup post .

152
répondu 5 revs, 4 users 43%anon 2015-04-23 18:35:03

les erreurs courantes que les gens font est 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 ne peut toujours exécuter de mémoire dans permgen.

les causes courantes de la perte de mémoire dans le 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 sur PermGen area et elles seront collectées lorsque Classloader qui les a chargées sera prêt pour la collecte des ordures. Dans le cas où Classloader a une fuite de mémoire que toutes les classes chargées par elle restera dans la mémoire et causera permGen outofmemory une fois que vous le répétez un couple de fois. L'exemple classique est Java.lang.OutOfMemoryError: PermGen Space in Tomcat .

il y a deux façons de résoudre ce problème:

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 PermGen Espace en utilisant JVM param -XX:MaxPermSize et -XX:PermSize .

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

65
répondu Peter 2014-07-08 16:27:33

utilisez le paramètre de ligne de commande -XX:MaxPermSize=128m pour un Sun JVM (remplaçant évidemment 128 pour n'importe quelle taille dont vous avez besoin).

39
répondu user17163 2011-03-07 09:46:57

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

35
répondu 3 revs, 3 users 50%bassist 2012-05-21 20:31:14

je , a ajouté -XX: MaxPermSize = 128m (vous pouvez tester ce qui fonctionne le mieux) pour VM Arguments comme je suis à l'aide de l'ide eclipse. Dans la plupart des JVM, PermSize par défaut est autour de 64MB qui court de la mémoire s'il y a trop de classes ou un grand nombre de chaînes dans le projet.

Pour eclipse, il est également décrite sur réponse .

étape 1 : double clic sur le serveur tomcat à serveurs Tab

enter image description here

étape 2 : Open launch Conf et ajouter -XX: MaxPermSize = 128m à la fin de VM arguments .

enter image description here

24
répondu prayagupd 2017-05-23 12:34:53

j'ai mis ma tête contre ce problème tout en déployant et en sous-déployant une application web complexe aussi, et j'ai pensé que je voudrais 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 sur undeploy, tout est censé se passer bien. Cependant, en réalité, ce n'est pas aussi simple.

ou d'autres classes créées pendant 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 statique à l'origine, aucun ramassage de déchets ne nettoiera cette référence - le ClassLoader, et toutes les classes qu'il est chargé, sont ici pour rester.

et après quelques redéploiements, nous rencontrons le OutOfMemoryError.

Maintenant, c'est devenu un assez grave problème. J'ai pu faire bien sûr, Tomcat est redémarré après chaque redéploiement, mais cela supprime l'ensemble du serveur, plutôt que seulement l'application étant redéployée, ce qui est souvent impossible.

donc à la place j'ai mis en place une solution en code, qui fonctionne sur Apache Tomcat 6.0. Je n'ai pas testé sur d'autres serveurs d'application, et dois souligner que il est très probable que cela ne fonctionne pas sans modification sur un autre serveur d'application .

j'aime aussi dire que personnellement je déteste ce code, et que personne ne devrait l'utiliser comme "solution rapide" si le code existant peut être modifié pour utiliser des méthodes d'arrêt et de nettoyage appropriées . Le seul moment où ceci 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.

en tout cas, continuez avec le code. Cela devrait être appelé à la point où l'application n'est pas déployée - comme la méthode de destruction d'une servlet ou (la meilleure approche) la méthode contexttdestroyed d'un Servlettextlistener.

//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
répondu Edward Torbett 2011-06-09 09:39:03

alternativement, vous pouvez passer à JRockit qui gère permgen différemment de sun jvm. Il a généralement une meilleure performance.

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

15
répondu Jeremy 2012-03-29 14:15:01

1) Augmenter la taille de la mémoire PermGen

La première chose que l'on peut faire est de faire la taille de la génération permanente espace de tas plus. Cela ne peut pas être fait avec les arguments JVM habituels –Xms(set initial heap size) et –Xmx(set maximum heap size), puisque comme mentionné, l'espace de tas de génération permanente est entièrement séparé de L'espace de tas de Java régulier., et ces arguments définissent l'espace pour cet espace Java heap régulier. Cependant, il existe des arguments qui peuvent être utilisés(au moins avec les jvms Sun/OpenJDK) pour augmenter la taille de la génération permanente:

 -XX:MaxPermSize=128m

par défaut est 64m.

2) Activer Le Balayage

une autre façon de prendre soin de cela pour de bon est de permettre aux classes d'être déchargées de sorte que votre PermGen ne s'épuise jamais:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

des trucs comme ça ont fait de la magie pour moi dans le passé. Une chose cependant, il y a une la performance des compromis en utilisant ceux qui, depuis permgen balaie fera comme un supplément de 2 demandes pour chaque demande que vous faites ou quelque chose le long de ces lignes. Vous aurez besoin d'é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

15
répondu faisalbhagat 2014-09-12 07:39:54

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 une application simple à tomcat. Je montrais le même problème, résolu comme suit.

dans eclipse aller à serveurs onglet double-cliquez sur le serveur enregistré dans mon cas tomcat 7.0, il ouvre les informations générales d'enregistrement de mon serveur de fichiers. Sous la rubrique " Informations générales" cliquez sur le lien "Open launch configuration" , ce qui ouvre l'exécution des options du serveur dans L'onglet Arguments dans les arguments VM ajoutés à la fin ces deux entrées

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

et prêt.

13
répondu Hugo Mendoza 2013-03-03 07:36:47

la réponse la plus simple de nos jours est D'utiliser Java 8.

il ne réserve plus de mémoire exclusivement pour L'espace PermGen, permettant à la mémoire PermGen de se mêler avec le pool de mémoire régulier.

gardez à l'esprit que vous devrez supprimer tous les paramètres de démarrage non standard -XXPermGen...=... JVM si vous ne voulez pas que Java 8 se plaint qu'ils ne font rien.

13
répondu Edwin Buck 2014-08-04 13:01:13

le message spatial java.lang.OutOfMemoryError: PermGen indique que la zone de mémoire de la génération permanente est épuisée.

toute application Java est autorisée à utiliser une quantité limitée de mémoire. La quantité exacte de mémoire que votre application particulière peut utiliser est spécifiée au démarrage de l'application.

la mémoire Java est séparée en différentes régions qui peuvent être vues dans l'image suivante:

enter image description here

Metaspace: un nouvel espace de mémoire est né

le JVM HotSpot JDK 8 utilise maintenant la mémoire native pour la représentation des métadonnées de classe et est appelé Metaspace; similaire à L'Oracle JRockit et IBM JVM.

la bonne nouvelle, c'est qu'il ne signifie plus java.lang.OutOfMemoryError: PermGen problèmes d'espace et pas besoin pour vous d'accorder et de surveiller cette mémoire l'espace à l'aide de Java_8_Download ou plus.

11
répondu Santosh Jadi 2018-04-18 10:42:41
  1. ouvrir tomcat7w à partir du répertoire bin de Tomcat ou taper Monitor Tomcat dans le menu Démarrer (une fenêtre tabbed s'ouvre avec diverses informations de service).
  2. dans la zone de texte des Options Java, Ajoutez cette ligne:

    -XX:MaxPermSize=128m
    
  3. régler le Pool de mémoire Initial à 1024 (optionnel).
  4. régler le Pool de mémoire Maximum à 1024 (optionnel).
  5. Cliquez Sur Ok.
  6. redémarrer le Service Tomcat.
8
répondu Lucky 2013-03-20 13:12:40

Perm gen erreur d'espace se produit en raison de l'utilisation d'un grand espace plutôt que jvm fourni de l'espace pour exécuter le code. La meilleure solution pour ce problème dans les systèmes D'exploitation UNIX est de modifier une certaine configuration sur le fichier bash. Les étapes suivantes résolvent le problème.

Exécution de la commande gedit .bashrc sur le terminal.

créer JAVA_OTPS variable avec la valeur suivante:

export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"

Enregistrer le fichier bash. Lancer la bash command exec terminal. Redémarrez le serveur.

j'espère que cette approche fonctionnera sur votre problème. Si vous utilisez une version Java inférieure à 8, ce problème se produit parfois. Mais si vous utilisez Java 8 le problème ne se produit jamais.

6
répondu Darshan 2014-09-15 14:18:25

augmenter la taille de la génération permanente ou modifier les paramètres GC n'aidera pas si vous avez une véritable fuite de mémoire. Si votre application ou une bibliothèque de tiers qu'il utilise, classe de fuites Chargeurs la seule solution réelle et permanente est de trouver cette fuite et de la réparer. Il ya un certain nombre d'outils qui peuvent vous aider, l'un des récents est Plumbr , qui vient de sortir une nouvelle version avec les capacités requises.

5
répondu Nikem 2012-07-12 12:48:00

aussi si vous utilisez log4j dans votre webapp, cochez ce paragraphe dans log4j documentation .

il semble que si vous utilisez PropertyConfigurator.configureAndWatch("log4j.properties") , vous causez des fuites de mémoire lorsque vous désactivez votre webapp.

5
répondu sermojohn 2016-10-28 12:04:58

j'ai une combinaison D'hibernation+Eclipse RCP, essayé d'utiliser -XX:MaxPermSize=512m et -XX:PermSize=512m et il semble que cela fonctionne pour moi.

4
répondu 2 revs, 2 users 67%Pankaj Shinde 2011-02-24 13:30:56

Set -XX:PermSize=64m -XX:MaxPermSize=128m . Plus tard, vous pouvez également essayer d'augmenter MaxPermSize . Espérons que ça marchera. La même fonctionne pour moi. Mettre seulement MaxPermSize n'a pas fonctionné pour moi.

4
répondu sandeep 2012-07-13 07:39:09

j'ai essayé plusieurs réponses et la seule chose qui a finalement fait le travail était cette configuration pour le plugin de compilateur dans le pom:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <fork>true</fork>
        <meminitial>128m</meminitial>
        <maxmem>512m</maxmem>
        <source>1.6</source>
        <target>1.6</target>
        <!-- prevent PermGen space out of memory exception -->
        <!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
    </configuration>
</plugin>

j'espère que celui-ci vous aidera.

4
répondu kiwilisk 2014-08-04 12:44:21

a résolu ce problème pour moi aussi; cependant, j'ai remarqué que les temps de redémarrage de servlet étaient beaucoup plus mauvais, donc bien qu'il était meilleur dans la production, il était en quelque sorte un frein dans le développement.

4
répondu Tim Howland 2016-10-28 14:08:16

La configuration de la mémoire dépend de la nature de votre application.

Que faites-vous?

Quelle est la quantité de transactions prédéfinies?

combien de données chargez-vous?

etc.

etc.

etc

probablement vous pourriez profiler votre application et commencer à nettoyer certains modules de votre application.

apparemment, cela peut se produire après redéploiement d'une application à quelques reprises

Tomcat dispose de Hot deploy mais consomme de la mémoire. Essayez de redémarrer votre conteneur de temps en temps. Aussi, vous aurez besoin de savoir la quantité de mémoire nécessaire pour exécuter en mode production, Cela semble un bon moment pour cette recherche.

3
répondu OscarRyz 2009-03-11 22:24:55

ils disent que la dernière version de Tomcat (6.0.28 ou 6.0.29) s'occupe de la tâche de redéploiement des servlets beaucoup mieux.

3
répondu Tony Ennis 2010-09-19 12:31:54

je rencontre exactement le même problème, mais malheureusement, aucune des solutions proposées a vraiment fonctionné pour moi. Le problème ne s'est pas produit pendant le déploiement, et je ne faisais pas de déploiements chauds.

dans mon cas, le problème s'est produit à chaque fois au même moment pendant l'exécution de mon application web, tout en se connectant (via hibernate) à la base de données.

ce lien (également mentionné plus haut) a fourni assez d'intérieur pour résoudre le problème. Déplacer le pilote JDBC - (mysql)-hors du WEB-INF et dans le dossier jre/lib/ext/ semble avoir résolu le problème. Ce n'est pas la solution idéale, car la mise à niveau vers un nouveau JRE vous obligerait à réinstaller le pilote. Un autre candidat qui pourrait causer des problèmes similaires est log4j, donc vous pourriez vouloir déplacer celui-ci aussi bien

3
répondu Maze 2011-03-19 13:19:39

dans ce cas, la première étape consiste à vérifier si le CG est autorisé à décharger des classes de PermGen. La JVM standard est plutôt conservatrice à cet égard – les classes naissent pour vivre éternellement. Ainsi, une fois chargées, les classes restent en mémoire même si aucun code ne les utilise plus. Cela peut devenir un problème lorsque l'application crée beaucoup de classes dynamiquement et les classes générées ne sont pas nécessaires pour des périodes plus longues. Dans ce cas, il peut être utile de permettre à la JVM de décharger les définitions de classe. Pour ce faire, il suffit d'ajouter un seul paramètre de configuration à vos scripts de démarrage:

-XX:+CMSClassUnloadingEnabled

par défaut, cette option est définie à false et pour l'activer, vous devez explicitement définir L'option suivante dans les options Java. Si vous activez CMSClassUnloadingEnabled, GC balaiera PermGen aussi et supprimera les classes qui ne sont plus utilisées. Gardez à l'esprit que cette option ne fonctionnera que lorsque UseConcMarkSweepGC est également activé en utilisant l'option ci-dessous. Donc, lors de L'exécution de ParallelGC ou, à Dieu ne plaise, GC série, assurez-vous que vous avez paramétré votre GC au CMS en spécifiant:

-XX:+UseConcMarkSweepGC
3
répondu sendon1982 2016-01-05 01:04:17

attribuer à Tomcat plus de mémoire n'est pas la bonne solution.

la bonne solution est de faire un nettoyage après que le contexte soit détruit et recréé (le déploiement à chaud). La solution est d'arrêter les fuites de mémoire.

si votre serveur Tomcat/Webapp vous dit que vous n'avez pas réussi à désinscrire les pilotes (JDBC), alors désinscrivez-les. Cela va arrêter les fuites de mémoire.

vous pouvez créer un ServletContextListener et le configurer en votre web.XML. Voici un exemple de ServletContextListener Servl:

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.Logger;

import com.mysql.jdbc.AbandonedConnectionCleanupThread;

/**
 * 
 * @author alejandro.tkachuk / calculistik.com
 *
 */
public class AppContextListener implements ServletContextListener {

    private static final Logger logger = Logger.getLogger(AppContextListener.class);

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        logger.info("AppContextListener started");
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        logger.info("AppContextListener destroyed");

        // manually unregister the JDBC drivers
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.info(String.format("Unregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                logger.info(String.format("Error unregistering driver %s", driver), e);
            }

        }

        // manually shutdown clean up threads
        try {
            AbandonedConnectionCleanupThread.shutdown();
            logger.info("Shutting down AbandonedConnectionCleanupThread");
        } catch (InterruptedException e) {
            logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
            e.printStackTrace();
        }        
    }
}

et ici vous le configurez dans votre web.xml:

<listener>
    <listener-class>
        com.calculistik.mediweb.context.AppContextListener 
    </listener-class>
</listener>  
3
répondu Alejandro Pablo Tkachuk 2016-05-20 04:06:53

"Ils" sont faux, parce que je suis en cours d'exécution 6.0.29 et ont le même problème, même après avoir réglé toutes les options. Comme Tim Howland l'a dit plus haut, ces options ne font que retarder l'inévitable. Ils me permettent de redéployer 3 fois avant de frapper l'erreur au lieu de chaque fois que je redéployer.

2
répondu Ross Peoples 2010-09-20 17:40:48

dans le cas où vous obtenez ceci dans l'IDE eclipse, même après avoir réglé les paramètres --launcher.XXMaxPermSize , -XX:MaxPermSize , etc, toujours si vous obtenez la même erreur, il est très probable que l'eclipse utilise une version buggée de JRE qui aurait été installé par des applications tierces et réglé par défaut. Ces versions buggy ne prennent pas les paramètres PermSize et donc peu importe ce que vous définissez, vous continuez toujours à avoir ces erreurs de mémoire. Donc, dans votre eclipse.ini ajouter l' paramètres suivants:

-vm <path to the right JRE directory>/<name of javaw executable>

assurez-vous également que vous définissez la JRE par défaut dans les préférences de l'eclipse à la version correcte de java.

2
répondu Hrishikesh Kumar 2010-11-18 13:21:04

la seule façon qui a fonctionné pour moi était avec le JVM JRockit. J'ai MyEclipse 8.6.

le tas de JVM stocke tous les objets générés par un programme Java en cours d'exécution. Java utilise l'opérateur new pour créer des objets, et la mémoire pour les nouveaux objets est allouée sur le tas au moment de l'exécution. La collecte des ordures est le mécanisme de libération automatique de la mémoire contenue par les objets qui ne sont plus référencés par le programme.

2
répondu user1985910 2013-01-21 23:26:29

j'avais un problème similaire. Le mien est JDK 7 + Maven 3.0.2 + Struts 2.0 + Google projet basé sur l'injection de dépendance GUICE.

chaque fois que j'ai essayé d'exécuter la commande mvn clean package , elle montrait l'erreur suivante et "L'échec de construction" occurred

org.Apache.maven.infaillible.util.SurefireReflectionException: java.lang.refléter.Invocationtexception cible; nichée l'exception est java.lang.refléter.InvocationTargetException: null Java.lang.refléter.Invocationtexception cible Causé par: java.lang.OutOfMemoryError: PermGen space

j'ai essayé tous les conseils et astuces utiles, mais malheureusement aucun n'a fonctionné pour moi. Ce qui a fonctionné pour moi est décrit étape par étape ci-dessous: = >

  1. allez à votre pom.xml
  2. recherche de <artifactId>maven-surefire-plugin</artifactId>
  3. Ajouter un nouvel élément <configuration> puis <argLine> sous-élément dans lequel passer -Xmx512m -XX:MaxPermSize=256m comme indiqué ci-dessous = >

<configuration> <argLine>-Xmx512m -XX:MaxPermSize=256m</argLine> </configuration>

Espérons que cela aide, bonne programmation :)

2
répondu NIKHIL CHAURASIA 2015-09-04 09:33:38