Traitement de l'erreur «java.lang.OutOfMemoryError: PermGen space»

1223

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

java.lang.OutOfMemoryError: espace PermGen

Il s'agit d'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 à quelques reprises.

Qu'est-ce qui la cause et que peut-on faire pour l'éviter? Comment résoudre le problème?

Chris
la source
J'ai combattu cela pendant des heures, mais je n'ai pas de bonnes nouvelles. Voir ma question connexe: stackoverflow.com/questions/1996088/… Vous pouvez toujours avoir une fuite de mémoire, par exemple, les classes ne sont pas récupérées car votre WebAppClassLoader n'est pas récupéré (il a une référence externe qui n'est pas effacée). l'augmentation de PermGen ne fera que retarder OutOfMemoryError, et autoriser le ramasse-miettes de classe est une condition préalable, mais ne remettra pas les classes de ramasse-miettes si leur chargeur de classe a encore des références.
Eran Medan
J'ai eu cette erreur lors de l'ajout de taglib d'affichage . La suppression a donc également résolu l'erreur. Pourquoi
mardi
Et comment avez-vous rencontré cela?
Thorbjørn Ravn Andersen
13
utilisez JDK 1.8: þ bienvenue dans le MetaSpace
Rytek
Si vous utilisez Windows, suivez ces instructions au lieu d'essayer de définir les indicateurs manuellement dans les fichiers de configuration. Cela définit correctement les valeurs du registre à appeler par Tomcat pendant l'exécution. stackoverflow.com/questions/21104340/…
MacGyver

Réponses:

563

La solution était d'ajouter ces drapeaux à la ligne de commande JVM au démarrage de Tomcat:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

Pour ce faire, arrêtez le service tomcat, puis accédez au répertoire Tomcat / bin et exécutez 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 devez exécuter:

tomcat6w //ES//servicename

servicename est le nom du serveur tel qu'il apparaît dans services.msc

Source: commentaire d'Orx sur les réponses agiles d'Eric .

Chris
la source
39
L'article ci-dessous suggère également -XX: + UseConcMarkSweepGC et -XX: MaxPermSize = 128m. my.opera.com/karmazilla/blog/2007/03/13/…
Taylor Leese
30
-XX: + CMSPermGenSweepingEnabled Cette option réduit les performances. Cela fait que chaque demande prend trois fois plus de temps que d'habitude sur nos systèmes. Utilisez avec précaution.
Eldelshell
10
travaillé pour moi - merci - je le fais sur Ubuntu 10.10 avec Tomcat6 - j'ai créé un nouveau fichier: /usr/share/tomcat6/bin/setenv.sh et y ai ajouté la ligne suivante: JAVA_OPTS = "- Xms256m -Xmx512m - XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled "- Tomcat redémarré à l'aide de: sudo /etc/init.d/tomcat6 start
sami
24
Au démarrage de tomcat 6.0.29, à partir de mon fichier journal catalina.out: "Veuillez utiliser CMSClassUnloadingEnabled à la place de CMSPermGenSweepingEnabled à l'avenir"
knb
222
Tout d'abord, ce serait formidable d'expliquer ce que ces drapeaux font vraiment. Dire simplement: "faites-le et profitez-en" ne suffit pas à mon humble avis.
Nikem
251

Vous feriez mieux d'essayer -XX:MaxPermSize=128Mplutô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 lors de l'exécution, il est plus probable qu'elles nécessitent un pool de mémoire plus grand que celui par défaut.

toesterdahl
la source
9
En fait, cela ne fera que reporter OOMError. Voir la réponse ci-dessous commencée par anon avec deux liens vers le blog de frankkieviet.
Rade_303
Ces options sont expliquées ici: oracle.com/technetwork/java/javase/tech/…
amos
153

Les erreurs PermGen du serveur d'applications qui se produisent après plusieurs déploiements sont probablement causées par des références détenues par 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înera la tenue de références par le chargeur de classe du serveur d'applications. Vous pouvez détecter ces fuites entre chargeurs de classes en utilisant des 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 repensant ou en éliminant leur utilisation. Les suspects habituels sont les bases de données, les enregistreurs et les autres bibliothèques au niveau du framework de base.

Voir les fuites de Classloader: l'exception redoutée "java.lang.OutOfMemoryError: PermGen space" , et en particulier son article de suivi .

anon
la source
3
Ce n'est qu'une vraie solution au problème, capable dans certains cas trop difficile à mettre en œuvre.
Rade_303
People.apache.org/~markt/presentations/… (du gestionnaire de versions de Tomcat !!) est une autre très bonne source .
gavenkoa
22
Bien que cela puisse théoriquement répondre à la question, il serait préférable d'inclure ici les parties essentielles de la réponse et de fournir le lien de référence.
Joachim Sauer du
68

Les gens commettent souvent des erreurs en pensant que l'espace de tas et l'espace de permgen sont identiques, ce qui n'est pas du tout vrai. Vous pouvez avoir beaucoup d'espace restant dans le tas, mais vous pouvez toujours manquer de mémoire dans permgen.

Les causes courantes d'OutofMemory dans PermGen sont ClassLoader. Chaque fois qu'une classe est chargée dans JVM, toutes ses métadonnées, ainsi que Classloader, sont conservées dans la zone PermGen et elles seront récupérées lorsque le Classloader qui les a chargées est prêt pour la collecte des ordures. Dans le cas où Classloader a une fuite de mémoire, toutes les classes chargées par celui-ci resteront en mémoire et provoqueront une permofen outofmemory une fois que vous le répéterez plusieurs fois. L'exemple classique est Java.lang.OutOfMemoryError: PermGen Space dans Tomcat .

Il existe maintenant 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. Augmentez la taille de PermGen Space en utilisant les paramètres JVM -XX:MaxPermSizeet -XX:PermSize.

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

Peter
la source
3
Comment passer param -XX:MaxPermSize and -XX:PermSize?? Je ne trouve pas catalina.bat. Ma version tomcat est 5.5.26.
Deckard
Comment trouver les fuites de mémoire du chargeur de classe? Recommandez-vous un outil?
Amit
@amit pour les recommandations d'outils, voir la réponse du wiki de la communauté sur cette question.
Barett
@Deckard allant dans le répertoire Tomcat / bin et exécutant tomcat6w.exe. Sous l'onglet "Java", ajoutez les arguments à la boîte "Options Java". Cliquez sur "OK"
Zeb
43

Utilisez le paramètre de ligne de commande -XX:MaxPermSize=128mpour une machine virtuelle Java Sun (en substituant évidemment 128 à la taille dont vous avez besoin).

user17163
la source
9
Le seul problème est que vous retardez simplement l'inévitable - à un moment donné, vous manquerez également d'espace libre. C'est une excellente solution pragmatique, mais elle ne la résout pas de manière permanente.
Tim Howland
la même chose se produit dans Eclipse et chaque fois que vous avez beaucoup de chargement de classe dynamique. les chargeurs de classe ne sont pas éliminés et vivent dans la génération permanente pour toute l'éternité
Matt
1
Je manquais de PermGen lors de l'exécution d'un travail Hudson particulièrement important ... cela m'a corrigé.
Enregistrer
10
@TimHowland, cela peut être un correctif permanent si la cause première n'est pas une fuite du chargeur de classe, juste trop de classes / données statiques dans votre application web.
Péter Török
a obtenu le même problème que HDave lors de la construction de jenkins / hudson à partir de la source.
louisgab
38

Essayez -XX:MaxPermSize=256met si cela persiste, essayez-XX:MaxPermSize=512m

bassiste
la source
56
et si cela persiste, essayez XX:MaxPermSize=1024m:)
igo
38
et si cela persiste, essayez XX: MaxPermSize = 2048m :)
Thomas
16
Et si cela persiste, repensez votre application !! Ou essayez XX: MaxPermSize = 4096m :)
Jonathan Airey
17
vous pouvez aussi essayer 8192m mais c'est un peu exagéré
Jacek Pietal
12
Overkill en effet - 640KB devrait être suffisant pour n'importe qui!
Joel Purra
28

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

Pour l'éclipse, il est également décrit à la réponse .

ÉTAPE 1 : Double-cliquez sur le serveur tomcat dans l' onglet Serveurs

entrez la description de l'image ici

ÉTAPE 2 : Ouvrez Launch Conf et ajoutez -XX: MaxPermSize = 128mà la fin des arguments VM existants .

entrez la description de l'image ici

prayagupd
la source
1
Merci pour votre meilleure réponse détaillée (Remarque: cliquez sur "Ouvrir la configuration de lancement" pour ouvrir la fenêtre "modifier la configuration" ... mais j'ai utilisé les paramètres suivants: "-XX: + CMSClassUnloadingEnabled -XX: + CMSPermGenSweepingEnabled"
Chris Sim
23

J'ai buté ma tête contre ce problème lors du déploiement et du retrait 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 lors du retrait, tout est censé bien disparaître. Cependant, en réalité, ce n'est pas aussi simple.

Une ou plusieurs des 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 récupération de place ne nettoiera cette référence - le ClassLoader et toutes les classes qu'il est chargé sont là pour rester.

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

Maintenant, c'est devenu un problème assez grave. Je pourrais m'assurer que Tomcat est redémarré après chaque redéploiement, mais cela supprime l'ensemble du serveur, plutôt que simplement l'application redéployée, ce qui n'est souvent pas faisable.

Au lieu de cela, j'ai mis en place une solution dans le code, qui fonctionne sur Apache Tomcat 6.0. Je n'ai testé sur aucun autre serveur d'applications et je dois souligner qu'il est très probable que cela ne fonctionne pas sans modification sur un autre serveur d'applications .

Je voudrais également dire que personnellement, je déteste ce code, et que personne ne devrait l'utiliser comme une «solution rapide» si le code existant peut être modifié pour utiliser des méthodes d'arrêt et de nettoyage appropriées . La seule fois où cela devrait être utilisé, c'est s'il existe 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 ne se déploie pas - comme la méthode destroy d'un servlet ou (la meilleure approche) la méthode contextDestroyed d'un 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();
Edward Torbett
la source
Je sais que cela fait plus de 8 ans que j'ai écrit cela, mais quelque part entre maintenant et maintenant, j'ai trouvé une cause et une solution plus profondes. En effet, bien que toutes les classes de la webapp appartiennent au chargeur de classe de contexte, le thread qui appelle le rappel de démarrage et d'arrêt appartient au chargeur de classe parent. Cela signifie que si le code d'arrêt initialise une variable locale de thread, le chargeur de classe parent finira par contenir une référence au chargeur de classe de contexte, empêchant un bon nettoyage.
Edward Torbett
Heureusement, il existe une solution très simple - déplacer tout le code actuellement dans la méthode d'arrêt dans la nouvelle méthode d'exécution d'un objet Thread. Ensuite, dans la méthode d'arrêt, démarrez ce thread et attendez qu'il se termine. Le code de nettoyage sera exécuté de manière identique, mais toutes les variables locales de thread resteront liées au chargeur de classe de contexte au lieu de fuir.
Edward Torbett
20

Le java.lang.OutOfMemoryError: PermGenmessage d'espace indique que la zone de mémoire de la génération permanente est épuisée.

Toutes les applications Java sont autorisées à 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:

entrez la description de l'image ici

Metaspace: un nouvel espace mémoire est né

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

La bonne nouvelle est que cela signifie plus de java.lang.OutOfMemoryError: PermGenproblèmes d'espace et plus besoin de régler et de surveiller cet espace mémoire à l'aide de Java_8_Download ou supérieur.

Santosh Jadi
la source
17

1) Augmenter la taille de la mémoire PermGen

La première chose que l'on peut faire est d'agrandir la taille de l'espace de stockage de génération permanente. Cela ne peut pas être fait avec les arguments JVM habituels –Xms (définir la taille initiale du segment) et –Xmx (définir la taille maximale du segment), car, comme mentionné, l'espace de segment de génération permanent est entièrement distinct de l'espace de segment Java standard et ces arguments sont définis l'espace pour cet espace de tas Java standard. Cependant, il existe des arguments similaires qui peuvent être utilisés (au moins avec les jvms Sun / OpenJDK) pour augmenter la taille du tas de génération permanente:

 -XX:MaxPermSize=128m

La valeur par défaut est 64 m.

2) Activer le balayage

Une autre façon de s'en occuper pour de bon est d'autoriser le déchargement des classes pour 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 un compromis de performance significatif dans leur utilisation, car les balayages 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

faisalbhagat
la source
Grand message de @faisalbhagat faisalbhagat.blogspot.com/2014/09/…
leomeurer
L'option 2 est excellente, mais sachez simplement qu'elle ne doit pas être utilisée dans des environnements de production. Il est généralement préférable de le conserver uniquement dans les environnements de développement. Cependant PermGen est supprimé à partir de Java 8 openjdk.java.net/jeps/122
hdost
16

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

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

Jeremy
la source
4
Certes, JRockit n'a pas de PermGen, mais cela n'aidera pas à long terme. Vous obtiendrez à la java.lang.OutOfMemoryError: There is insufficient native memoryplace.
stracktracer
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 sur tomcat. Je montrais le même problème ici, je l'ai résolu comme suit.

Dans eclipse, allez dans l' onglet serveurs double-cliquez sur le serveur enregistré dans mon cas tomcat 7.0, il ouvre mon serveur de fichiers Informations générales d'enregistrement. Dans la section "Informations générales" cliquez sur le lien "Ouvrir la configuration de lancement" , cela ouvre l'exécution des options du serveur dans l'onglet Arguments des arguments VM ajoutés à la fin de ces deux entrées

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

et prêt.

Hugo Mendoza
la source
14

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élanger avec le pool de mémoire normal.

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

Edwin Buck
la source
Bonjour, cette réponse a déjà été donnée: stackoverflow.com/a/22897121/505893 . Veuillez supprimer votre réponse, pour plus de clarté. Si nécessaire, vous pouvez améliorer la réponse que j'ai mentionnée. Merci;)
bleuâtre
6
@bluish Merci d'avoir signalé cela; cependant, cette réponse va de travers en parlant des OutOfMemoryExceptions et des métadonnées qui fuient. Il ne mentionne pas non plus les points très importants de la suppression de l'option PermGen. Bref, je ne suis pas sûr que j'améliorerais la réponse, mais plutôt la réécrire. S'il ne s'agissait que d'une retouche rapide, je me sentirais moins hésitant, mais il semblerait que ce serait bien plus qu'une retouche rapide, et je détesterais offenser l'auteur d'origine. Pourtant, cette liste de réponses est le dîner d'un chien en désordre, et peut-être que tuer mon message serait le mieux de toute façon.
Edwin Buck
8
  1. Ouvrez tomcat7w à partir du répertoire bin de Tomcat ou tapez Monitor Tomcat dans le menu Démarrer (une fenêtre à onglets s'ouvre avec diverses informations de service).
  2. Dans la zone de texte Options Java, ajoutez cette ligne:

    -XX:MaxPermSize=128m
  3. Définissez le pool de mémoire initiale sur 1024 (facultatif).
  4. Définissez le pool de mémoire maximum sur 1024 (facultatif).
  5. Cliquez sur OK.
  6. Redémarrez le service Tomcat.
chance
la source
6

Une erreur d'espace de génération permanente se produit en raison de l'utilisation d'un grand espace plutôt que de l'espace fourni par jvm pour exécuter le code.

La meilleure solution à ce problème dans les systèmes d'exploitation UNIX consiste à modifier une configuration sur le fichier bash. Les étapes suivantes résolvent le problème.

Exécutez la commande gedit .bashrcsur le terminal.

Créez une JAVA_OTPSvariable avec la valeur suivante:

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

Enregistrez le fichier bash. Exécutez la commande exec bash sur le 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.

Darshan
la source
5

L'augmentation de la taille de la génération permanente ou la modification des paramètres GC n'aidera PAS si vous avez une vraie fuite de mémoire. Si votre application ou une bibliothèque tierce qu'elle utilise, les chargeurs de classe de fuites, la seule solution réelle et permanente est de trouver cette fuite et de la corriger. Il existe un certain nombre d'outils qui peuvent vous aider, l'un des plus récents est Plumbr , qui vient de publier une nouvelle version avec les capacités requises.

Nikem
la source
5

De plus, si vous utilisez log4j dans votre application Web, consultez ce paragraphe dans la documentation de log4j .

Il semble que si vous utilisez PropertyConfigurator.configureAndWatch("log4j.properties"), vous causez des fuites de mémoire lorsque vous annulez le déploiement de votre application Web.

sermojohn
la source
4

J'ai une combinaison de mise en veille prolongée + Eclipse RCP, essayé d' utiliser -XX:MaxPermSize=512met -XX:PermSize=512mil semble fonctionner pour moi.

Pankaj Shinde
la source
4

Set -XX:PermSize=64m -XX:MaxPermSize=128m. Plus tard, vous pouvez également essayer d'augmenter MaxPermSize. J'espère que ça marchera. La même chose fonctionne pour moi. Le réglage MaxPermSizen'a pas fonctionné pour moi.

sandeep
la source
4

J'ai essayé plusieurs réponses et la seule chose qui a finalement fait le travail était cette configuration pour le plugin du 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 aide.

kiwis
la source
"argLine" n'est pas reconnu par maven-compiler-plugin 2.4. il ne prend en charge que "compilerArgument", ce qui donne l'erreur: <compilerArgument> -XX: MaxPermSize = 256m </compilerArgument> [ERREUR] Échec de l'exécution de javac, mais n'a pas pu analyser l'erreur: javac: indicateur non valide: -XX: MaxPermSize = 256m Utilisation : javac <options> <fichiers source>
Alex
Si votre phase de compilation est à court de permgen, définissez <compilerArgument> sur le plugin maven-compiler-plugin. Si les tests unitaires sont en cours d'exécution de permgen, définissez <argLine> dans le plugin maven-surefire
qwerty
4

a résolu cela aussi pour moi; cependant, j'ai remarqué que les temps de redémarrage des servlets étaient bien pires, donc même s'il était meilleur en production, c'était une sorte de ralentissement dans le développement.

Tim Howland
la source
3

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

Qu'est-ce que tu fais?

Quel est le montant des transactions nécessaires?

Combien de données chargez-vous?

etc.

etc.

etc

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

Apparemment, cela peut se produire après avoir redéployé une application plusieurs fois

Tomcat a un déploiement à chaud mais il consomme de la mémoire. Essayez de redémarrer votre conteneur de temps en temps. Vous aurez également besoin de connaître la quantité de mémoire nécessaire pour fonctionner en mode production, cela semble un bon moment pour cette recherche.

OscarRyz
la source
3

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

Tony Ennis
la source
3

Je rencontre exactement le même problème, mais malheureusement aucune des solutions suggérées n'a vraiment fonctionné pour moi. Le problème ne s'est pas produit pendant le déploiement, et je ne faisais aucun déploiement à chaud.

Dans mon cas, le problème s'est produit à chaque fois au même moment lors de l'exécution de mon application web, lors de la connexion (via hibernate) à la base de données.

Ce lien (également mentionné précédemment) a fourni suffisamment d'informations internes pour résoudre le problème. Le déplacement du 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 JRE plus récent vous obligerait à réinstaller le pilote. Un autre candidat qui pourrait causer des problèmes similaires est log4j, vous pouvez donc aussi déplacer celui-ci

2 tours
la source
Si vous ne souhaitez pas inclure le pilote dans jre / lib / ext, vous pouvez probablement obtenir les mêmes résultats en incluant le pilote dans votre chemin de classe de démarrage du conteneur. java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap.jar container.Start
Scot
3

La première étape dans ce cas consiste à vérifier si le GC 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 dynamiquement de nombreuses classes et que les classes générées ne sont pas nécessaires pour des périodes plus longues. Dans un tel cas, il peut être utile d'autoriser la JVM à décharger les définitions de classe. Cela peut être réalisé en ajoutant un seul paramètre de configuration à vos scripts de démarrage:

-XX:+CMSClassUnloadingEnabled

Par défaut, ce paramètre est défini sur false et pour l'activer, vous devez définir explicitement l'option suivante dans les options Java. Si vous activez CMSClassUnloadingEnabled, GC va également balayer PermGen et supprimer les classes qui ne sont plus utilisées. Gardez à l'esprit que cette option ne fonctionnera que lorsque UseConcMarkSweepGC est également activé à l'aide de l'option ci-dessous. Donc, lorsque vous exécutez ParallelGC ou, Dieu nous en préserve, Serial GC, assurez-vous que vous avez défini votre GC sur CMS en spécifiant:

-XX:+UseConcMarkSweepGC
sendon1982
la source
3

Attribuer plus de mémoire à Tomcat n'est PAS la bonne solution.

La bonne solution consiste à effectuer un nettoyage une fois le contexte 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 indique que l'échec de l'annulation de l'enregistrement des pilotes (JDBC) a échoué, annulez leur enregistrement. Cela arrêtera les fuites de mémoire.

Vous pouvez créer un ServletContextListener et le configurer dans votre web.xml. Voici un exemple de ServletContextListener:

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>  
Alejandro Pablo Tkachuk
la source
2

«Ils» sont faux car j'utilise 6.0.29 et j'ai le même problème même après avoir défini toutes les options. Comme Tim Howland l'a dit plus haut, ces options ne font que repousser l'inévitable. Ils me permettent de redéployer 3 fois avant de frapper l'erreur au lieu de chaque fois que je redéploie.

Ross Peoples
la source
2

Si vous obtenez cela dans l'IDE de l'éclipse, même après avoir défini les paramètres --launcher.XXMaxPermSize, -XX:MaxPermSizeetc., toujours si vous obtenez la même erreur, il est très probable que l'éclipse utilise une version boguée de JRE qui aurait été installée par certains applications tierces et définies par défaut. Ces versions de buggy ne récupèrent pas les paramètres PermSize et donc peu importe ce que vous définissez, vous continuez à obtenir ces erreurs de mémoire. Donc, dans votre eclipse.ini, ajoutez les paramètres suivants:

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

Assurez-vous également de définir le JRE par défaut dans les préférences de l'éclipse sur la version correcte de java.

Hrishikesh Kumar
la source
2

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

Le tas de la JVM stocke tous les objets générés par un programme Java en cours d'exécution. Java utilise l' newopérateur 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. Le garbage collection 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.

utilisateur1985910
la source
2

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

Chaque fois que j'essayais d'exécuter la mvn clean packagecommande, il montrait l'erreur suivante et "BUILD FAILURE" se produisait

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; l'exception imbriquée est java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException Provoqué par: java.lang.OutOfMemoryError: espace PermGen

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

  1. Accédez à votre pom.xml
  2. Rechercher <artifactId>maven-surefire-plugin</artifactId>
  3. Ajoutez un nouvel <configuration>élément puis un <argLine>sous-élément dans lequel passer -Xmx512m -XX:MaxPermSize=256mcomme indiqué ci-dessous =>

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

J'espère que ça aide, bonne programmation :)

NIKHIL CHAURASIA
la source