Que fait réellement l'indicateur JVM CMSClassUnloadingEnabled?

183

Je ne peux pas pour la vie de moi trouver une définition de ce que CMSClassUnloadingEnabledfait réellement l' indicateur Java VM , autre que quelques définitions de haut niveau très floues telles que "se débarrasse de vos problèmes PermGen" ( ce qui n'est pas le cas , btw).

J'ai regardé sur le site de Sun / Oracle, et même la liste des options ne dit pas vraiment ce qu'elle fait.

Sur la base du nom de l'indicateur, je suppose que le CMS Garbage Collector ne décharge pas par défaut les classes, et cet indicateur l'active - mais je ne peux pas en être sûr.

Riches
la source

Réponses:

219

Mise à jour Cette réponse est pertinente pour Java 5-7, Java 8 a corrigé ce problème: https://blogs.oracle.com/poonam/about-g1-garbage-collector,-permanent-generation-and-metaspace Félicitations aller à mt. uulu

Pour Java 5-7:

Le look standard d'Oracle / Sun VM sur le monde est le suivant: les classes sont éternelles. Alors une fois chargés, ils restent en mémoire même si personne ne s'en soucie plus. Ce n'est généralement pas un problème puisque vous n'avez pas autant de classes purement "setup" (= utilisées une fois pour la configuration et plus jamais). Donc, même s'ils occupent 1 Mo, peu importe.

Mais dernièrement, nous avons des langages comme Groovy, qui définissent les classes au moment de l'exécution. Chaque fois que vous exécutez un script, une (ou plusieurs) nouvelles classes sont créées et elles restent pour toujours dans PermGen. Si vous exécutez un serveur, cela signifie que vous avez une fuite de mémoire.

Si vous activez CMSClassUnloadingEnabledle GC balayera PermGen aussi et supprimera les classes qui ne sont plus utilisées.

[EDIT] Vous devrez également activer UseConcMarkSweepGC(merci à Sam Hasler ). Voir cette réponse: https://stackoverflow.com/a/3720052/2541

Aaron Digulla
la source
17
Selon stackoverflow.com/a/3720052/2541 pour CMSClassUnloadingEnabledavoir un impact, UseConcMarkSweepGCdoit également être défini
Sam Hasler
1
Je ne sais pas comment cela affecte l'idée d'utiliser UseConcatSweepGC, mais il semble qu'un bogue a été récemment corrigé dans CMSClassUnloadingEnabled. Il est remarqué comme corrigé ici: bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000325
Bill Rosmus
3
@Kevin: Oui, certainement. Voir en bas de groovy.codehaus.org/Running : "Groovy crée des classes dynamiquement, mais la VM Java par défaut ne GC le PermGen. Si vous utilisez Java 6 ou version ultérieure, ajoutez -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC. UseConcMarkSweepGCEst nécessaire pour l'activer CMSClassUnloadingEnabled."
Aaron Digulla
1
Un bon article sur l'utilisation conjointe de UseConcMarkSweepGC et CMSClassUnloadingEnabled. blog.redfin.com/devblog/2012/06/…
Victor
1
n'est plus valable pour la version 1.8: blogs.oracle.com/poonam/…
mt.uulu
35

Selon le billet de blog La liste la plus complète des options -XX pour Java JVM , elle détermine si le déchargement de classe est activé sous le garbage collector CMS. La valeur par défaut est false. Il est une autre option appelée ClassUnloadingqui esttrue par défaut qui (probablement) affecte les autres éboueurs.

L'idée est que si le GC détecte qu'une classe précédemment chargée n'est plus utilisée nulle part dans la JVM, il peut récupérer la mémoire utilisée pour contenir le bytecode et / ou le code natif des classes.

La définition de CMSClassUnloadingEnabled peut vous aider à résoudre votre problème de permgen si vous utilisez actuellement le collecteur CMS . Mais il est probable que vous n'utilisiez pas le CMS ou que vous ayez une véritable fuite de mémoire liée au chargeur de classe. Dans ce dernier cas, votre classe n'apparaîtra jamais au GC comme inutilisée ... et ne sera donc jamais déchargée.


Aaron Digulla dit que "les cours sont éternels". Ce n'est pas strictement vrai, même dans le monde purement Java. En fait, la durée de vie d'une classe est liée à son chargeur de classe. Donc, si vous pouvez faire en sorte qu'un chargeur de classe soit récupéré (et ce n'est pas toujours une chose facile à faire), les classes qu'il a chargées seront également récupérées.

En fait, c'est ce qui se passe lorsque vous effectuez un redéploiement à chaud d'une application Web. (Ou du moins, c'est ce qui devrait arriver, si vous pouvez éviter les problèmes qui conduisent à une fuite de stockage permgen.)

Stephen C
la source
24

Un exemple où cela est utile:

La configuration -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabledsur notre JVM Weblogic 10.3 a aidé à résoudre un problème où l'implémentation JAX-WS créait une nouvelle classe de proxy pour chaque appel de service Web, conduisant finalement à des erreurs de mémoire insuffisante.

Ce n'était pas anodin à retracer. Le code suivant renvoyait toujours la même classe proxy pourport

final MyPortType port = 
Service.create(
        getClass().getResource("/path/to.wsdl"), 
        new QName("http://www.example.com", "MyService"))
    .getPort(
        new QName("http://www.example.com", "MyPortType"), 
        MyPortType.class);

En interne, ce proxy était délégué à une instance de weblogic.wsee.jaxws.spi.ClientInstance, qui était à nouveau déléguée à une nouvelle $Proxy[nnnn]classe où nétait incrémentée à chaque appel. Lors de l'ajout des indicateurs, nétait toujours incrémenté, mais au moins ces classes temporaires ont été supprimées de la mémoire.

Sur une note plus générale, cela peut être très utile lors de l'utilisation intensive de la réflexion Java et des proxies via java.lang.reflect.Proxy

Lukas Eder
la source
+1 pour partager une expérience réelle. Nous avons également eu ce problème sur torquebox où le serveur a généré un grand nombre de classes en raison des processus de compilation JRuby.
nurettin
7
notez également que -XX:+CMSPermGenSweepingEnabledest obsolète en faveur de-XX:+CMSClassUnloadingEnabled
nurettin
3
Une vraie solution à ce problème est de créer le port une fois et de le réutiliser. C'est ainsi que JAX-WS est censé être utilisé. Le port est également 100% thread-safe.
rustyx
@rustyx: Pouvez-vous soutenir cette affirmation avec un lien faisant autorité? J'ai toujours été très prudent de réutiliser les proxies et les stubs des services Web ... Par exemple, voir les clauses de non-responsabilité Apache CXF . Ou cette question
Lukas Eder
1
@rukavitsya: Comme je l'ai dit dans ma réponse. Chaque fois que j'ai appelé la logique ci-dessus, un nouveau proxy a été créé
Lukas Eder