java8 "de java.lang.OutOfMemoryError: Metaspace"

après avoir changé notre application java (services tournant sur Tomcat) JRE de Java 7 à Java 8, nous avons commencé à voir java.lang.OutOfMemoryError: Metaspace après quelques jours de circulation intense.

L'usage de tas était correct. Metaspace saute après un moment où le même flux de code a été exécuté pendant les tests de performance.

quelles sont les causes possibles du problème de mémoire de metaspace?

paramètres actuels:

-server -Xms8g -Xmx8g -XX:MaxMetaspaceSize=3200m  -XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC -XX:MaxGCPauseMillis=1000 
-XX:+DisableExplicitGC -XX:+PrintGCDetails 
-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=7 -XX:NewSize=5004m 
-XX:MaxNewSize=5004m -XX:MaxTenuringThreshold=12 
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintFlagsFinal  
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution 
-XX:+PrintGCCause -XX:+PrintAdaptiveSizePolicy 
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=200M 

aussi la demande a usage intensif de la réflexion. Nous utilisons également un chargeur de classe personnalisé. Tous fonctionnaient bien à java 7.

17
demandé sur Jane 2016-03-17 07:39:43

2 réponses

je suppose que vous pouvez créer le problème avec la même requête (ensemble de requêtes) sur une période de temps. C'est une bonne chose que vous avez MaxMetaspaceSize défini, sinon app utilisera la mémoire native jusqu'à ce qu'il court pour se développer. Mais je commencerai par les étapes suivantes:

  1. vérifiez si votre nombre de classes qui sont chargées dans JVM continue de croître pour la même requête lorsque vous l'envoyez au serveur plusieurs fois. Si oui, il se peut que vous créiez des classes dynamiques qui provoqueraient une croissance dans classes chargées dans metaspace. Eh bien, comment vérifier le nombre de classes chargées, vous pouvez utiliser visualvm pour vous connecter au serveur en utilisant JMX ou exécuter localement pour simuler. Je mentionnerai les étapes pour local, mais pour la fixation à distance JMX, vous devez ajouter ce qui suit aux paramètres JVM à application et start it et Remote connect sur le port 9999 et avec-XX:+UnlockDiagnosticVMOptions.
   -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -XX:+UnlockDiagnosticVMOptions

une fois que vous avez le visualvm (jvisualvm) connecté à la JVM, cliquez sur surveiller et voir le nombre de classes chargées. Là vous pouvez surveiller le tas aussi bien que metaspace. Mais je vais ajouter les autres outils pour surveiller étroitement le metaspace.

  1. aussi une fois que vous êtes connecté à la jvm, vous pouvez prendre un instantané tas et découvrir les classes chargées en utilisant OQL. Ainsi, avant de faire un saut en tas, arrêtez les requêtes vers le serveur , de sorte que vous n'attrapez pas de code de requête/exécution de vol et leurs objets associés, mais ce n'est pas nécessaire. Si après avoir exécuté plusieurs fois le même ensemble de requêtes , à l'intérieur de visualvm , dans l'espace "monitor", cliquez sur "Heap Dump" en haut à droite". Puis ouvrez/chargez le snapshot, et vous verrez l'option à la console OQL. Et vous verriez quelques requêtes OQL prédéfinies sur le panneau du bas à droite sous analyse de permgen. Lancez la requête nommée "classloader loaded class histogram", je suppose que cela donnera le nombre de classes chargées par chaque classloader. Vous pouvez l'utiliser pour trouver quel classloader charge classe.

sélection de carte de tri ((carte(tas.les objets (java.lang.Chargeur de classe'), '{loader: c', count:.classe.elementCount }'), ' lhs.le comte < rhs.le comte'), 'toHtml (it)+"

"')

mais la requête ci-dessus nommée "classloader loaded class" sera lente, ce qui montrera en fait les classes chargées par chaque classloader.

select { loader: cl,
             classes: filter(map(cl.classes.elementData, 'it'), 'it != null') }
    from instanceof java.lang.ClassLoader cl
  1. essayez de tracer la croissance dans metaspace zone. Nous allons maintenant utiliser jconsole et quelque chose de nouveau que java a: jmc (java mission de contrôle). Vous pouvez utiliser jconsole pour vous connecter à jvm (local ou distant) et une fois que vous êtes connecté allez dans l'onglet mémoire et vous pouvez surveiller la croissance non tas là, qui devrait avoir metaspace et le cache de code et l'espace de classe comprimé. Et maintenant vous connecter

jmc

pour vous connecter à la VM, puis une fois que vous êtes connectés, cliquez sur "commandes de Diagnostic" dans le JMC qui se trouve en haut à droite. Depuis, nous avons activé UnlockDiagnosticVMOptions, GC.class_stats pourrait être exécuté. Vous pouvez l'exécuter avec afficher toutes les colonnes et imprimer dans csv. Si la commande va ressembler à ça:

GC.class_stats -all=true -csv=true

et ensuite vous pouvez comparer les statistiques de classe sur différentes périodes et trouver quelles classes causent des problèmes(croissance de metaspace) ou quelles classes ont des informations connexes( données de méthode/méthode) dans metaspace. Comment analyser les sorties csv recueillies à temps: eh bien, je prendrais que csv et le charger en deux tableau similaire (représentant csv) dans une base de données ou un autre endroit pour comparer GC.les sorties csv de class_stats où je peux exécuter du SQL ou tout autre outil d'analyse. Cela donnerait une meilleure idée de ce qui pousse exactement dans metaspace. La classe GC stats a colonnes suivantes:

il aide. Il apparaît également que le bogue peut être en Java 8 s'il ne cause pas de fuite en 1.7.

en outre, les classes ne seront pas déchargées de metaspace si quelqu'un détient une référence à classloader. Si vous savez que vos classloaders sont censés être Geded et que personne ne devrait détenir la référence de votre class loader, vous pouvez retourner à tas dump dans visualvm et cliquer sur l'instance class loader et clic droit pour trouver "GC root le plus proche" qui vous indiquera qui détient la référence les chargeurs de classes.

17
répondu dillip pattnaik 2016-03-29 20:54:30

nous avons eu un problème similaire et la cause principale était que les fichiers de classe de 60K sont chargés dans la mémoire de metaspace, mais rien n'est déchargé.Ajouter ci-dessous JVM arg réglé question.

-Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true

https://issues.apache.org/jira/browse/CXF-2939

Espérons que cette aide.

3
répondu user1550159 2017-06-29 16:58:24