web-dev-qa-db-fra.com

Réglage -XX: + DisableExplicitGC en production: qu'est-ce qui pourrait mal tourner?

nous venons de tenir une réunion pour résoudre certains problèmes de performances dans une application Web utilisée pour calculer les taux d'assurance. Les calculs sont implémentés dans un module C/C++, qui est également utilisé dans d'autres progiciels. Pour le rendre disponible en tant que service Web, un wrapper Java a été implémenté qui expose une interface basée sur XML et appelle le module C/C++ via JNI.

Les mesures ont montré que plusieurs secondes ont été consacrées à chaque calcul à l'intérieur de la partie Java. Mon premier choix a donc été d'activer la journalisation de la collecte des ordures dans la machine virtuelle. Nous avons pu voir immédiatement que beaucoup d'arrêts du monde des GC complets ont été créés. À ce propos, le développeur de la partie Java nous a dit avoir fait une System.gc() à plusieurs reprises "pour s'assurer que la mémoire est libérée après utilisation" .

OK, je ne développerai pas cette déclaration plus loin ... ;-)

Nous avons ensuite ajouté -XX:+DisableExplicitGC Ci-dessus aussi les arguments VMs et relancé les tests. Cela a gagné environ 5 secondes par calcul.

Comme nous ne pouvons pas changer le code en supprimant tous ces appels System.gc() à ce stade de notre processus de publication, nous pensons ajouter -XX:+DisableExplicitGC En production jusqu'à ce qu'un nouveau Jar puisse être créé.

Maintenant, la question est: pourrait-il y avoir un risque à le faire? La seule chose à laquelle je peux penser est que Tomcat utilise System.gc() en interne lors du redéploiement, mais ce n'est qu'une supposition. Y a-t-il d'autres dangers à venir?

36
Axel

Vous n'êtes pas seul à corriger les événements du GC Stop-the-world en définissant le -XX:+DisableExplicitGC drapeau. Malheureusement (et malgré les avertissements dans la documentation), de nombreux développeurs décident qu'ils savent mieux que la JVM quand collecter de la mémoire et introduire exactement ce type de problème.

Je connais de nombreux cas où le -XX:+DisableExplicitGC amélioré l'environnement de production et zéro cas où il y avait des effets secondaires négatifs.

La chose sûre à faire est d'exécuter votre code de production actuel, sous charge, avec cet indicateur défini dans un environnement de test de stress et d'effectuer un cycle d'assurance qualité normal.

Si vous ne pouvez pas le faire, je dirais que le risque de mettre le drapeau est inférieur au coût de ne pas le mettre dans la plupart des cas.

32
Eric J.

J'ai été aux prises avec ce même problème, et sur la base de toutes les informations que j'ai pu trouver, il semble y avoir un certain risque. D'après les commentaires sur votre message d'origine de @millimoose, ainsi que https://bugs.openjdk.Java.net/browse/JDK-6200079 , il semble que le paramètre -XX: + DisableExplicitGC serait une mauvaise idée si les tampons directs NIO sont utilisés. Il semble qu'ils soient utilisés dans l'implémentation interne du serveur d'application Websphere 8.5 que nous utilisons. Voici la trace de pile que j'ai pu capturer lors du débogage:

3XMTHREADINFO      "WebContainer : 25" J9VMThread:0x0000000006FC5D00, j9thread_t:0x00007F60E41753E0, Java/lang/Thread:0x000000060B735590, state:R, prio=5
3XMJAVALTHREAD            (Java/lang/Thread getId:0xFE, isDaemon:true)
3XMTHREADINFO1            (native thread ID:0x1039, native priority:0x5, native policy:UNKNOWN)
3XMTHREADINFO2            (native stack address range from:0x00007F6067621000, to:0x00007F6067662000, size:0x41000)
3XMCPUTIME               CPU usage total: 80.222215853 secs
3XMHEAPALLOC             Heap bytes allocated since last GC cycle=1594568 (0x1854C8)
3XMTHREADINFO3           Java callstack:
4XESTACKTRACE                at Java/lang/System.gc(System.Java:329)
4XESTACKTRACE                at Java/nio/Bits.syncReserveMemory(Bits.Java:721)
5XESTACKTRACE                   (entered lock: Java/nio/Bits@0x000000060000B690, entry count: 1)
4XESTACKTRACE                at Java/nio/Bits.reserveMemory(Bits.Java:766(Compiled Code))
4XESTACKTRACE                at Java/nio/DirectByteBuffer.<init>(DirectByteBuffer.Java:123(Compiled Code))
4XESTACKTRACE                at Java/nio/ByteBuffer.allocateDirect(ByteBuffer.Java:306(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/buffermgmt/impl/WsByteBufferPoolManagerImpl.allocateBufferDirect(WsByteBufferPoolManagerImpl.Java:706(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/buffermgmt/impl/WsByteBufferPoolManagerImpl.allocateCommon(WsByteBufferPoolManagerImpl.Java:612(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/buffermgmt/impl/WsByteBufferPoolManagerImpl.allocateDirect(WsByteBufferPoolManagerImpl.Java:527(Compiled Code))
4XESTACKTRACE                at com/ibm/io/async/ResultHandler.runEventProcessingLoop(ResultHandler.Java:507(Compiled Code))
4XESTACKTRACE                at com/ibm/io/async/ResultHandler$2.run(ResultHandler.Java:905(Compiled Code))
4XESTACKTRACE                at com/ibm/ws/util/ThreadPool$Worker.run(ThreadPool.Java:1864(Compiled Code))
3XMTHREADINFO3           Native callstack:
4XENATIVESTACK               (0x00007F61083DD122 [libj9prt26.so+0x13122])
4XENATIVESTACK               (0x00007F61083EA79F [libj9prt26.so+0x2079f])
....

Quelles sont exactement les ramifications complètes de la définition de -XX: + DisableExplicitGC lorsque des tampons NIO à octets directs ne sont pas encore tout à fait clairs pour moi (cela introduit-il une fuite de mémoire?), Mais il semble au moins y avoir un risque Là. Si vous utilisez un serveur d'applications autre que Websphere, vous pouvez vérifier que le serveur d'applications lui-même n'appelle pas System.gc () via NIO avant de le désactiver. J'ai une question connexe qui, je l'espère, obtiendra des éclaircissements sur l'impact exact sur les bibliothèques NIO ici: Impact du paramètre -XX: + DisableExplicitGC lorsque des tampons directs NIO sont utilisés

Soit dit en passant, Websphere semble également invoquer manuellement System.gc () plusieurs fois pendant le processus de démarrage, généralement deux fois dans les deux premières secondes après le lancement du serveur d'application, et une troisième fois dans les 1-2 premières minutes (peut-être lorsque l'application est en cours de déploiement). Dans notre cas, c'est pourquoi nous avons commencé à enquêter en premier lieu, car il semble que tous les appels System.gc () proviennent directement du serveur d'application, et jamais de notre code d'application.

Il convient également de noter qu'en plus des bibliothèques NIO, l'implémentation interne JDK de la récupération de place distribuée RMI appelle également System.gc (): appels System.gc () inexpliqués en raison de l'invocation de méthode distante - System.gc () appels par les API principales

Si l'activation de -XX: + DisableExplicitGC causera également des ravages avec RMI DGC, je ne sais pas trop. La seule référence que j'ai pu trouver qui traite même de ceci est la première référence ci-dessus, qui indique

"Cependant, dans la plupart des cas, une activité régulière du GC est suffisante pour une DGC efficace"

Ce qualificatif `` dans la plupart des cas '' me semble extrêmement délirant, donc encore une fois, il semble qu'il y ait au moins un risque de simplement couper tous les appels System.gc (), et vous feriez mieux de réparer les appels dans votre code si possible et en les fermant entièrement en dernier recours.

2
rscarter

Si tu utilises -XX:+DisableExplicitGCet utilisez CMS, vous voudrez peut-être utiliser -XX:+CMSClassUnloadingEnabled également pour limiter une autre raison pour les GC complets (c'est-à-dire que le PermGen est plein). En dehors de cela, je n'ai pas eu de problèmes en utilisant l'option, bien que je sois passé à l'utilisation de -XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses, parce que ma seule cause de GC explicites était RMI, pas le code d'application.

1
Frank Pavageau