Optimisation des performances de la JVM pour les grandes applications


Les paramètres JVM par défaut ne sont pas optimaux pour l'exécution d'applications volumineuses. Toute idée de personnes qui l'ont réglé sur une application réelle serait utile. Nous exécutons l'application sur une machine Windows 32 bits, où la machine virtuelle java client est utilisée par défaut. Nous avons ajouté-serveur et changé le NewRatio à 1: 3 (Une plus grande jeune génération).

D'autres paramètres / réglages que vous avez essayés et trouvés utiles?

[Update] Le type spécifique d'application que je suis parler est une application serveur qui sont rarement arrêt, en prenant au moins-Xmx1024m. Supposons également que l'application est déjà profilée. Je cherche des directives générales en termes de Performance JVM uniquement.

Author: amit, 2009-02-19

7 answers

Il y a de grandes quantités de cette information autour.

Tout d'abord, profilez le code avant de régler la JVM.

Deuxièmement, lisez attentivement la documentation JVM; il y a beaucoup de sortes de "légendes urbaines" autour. Par exemple, l'indicateur-server n'aide que si la JVM reste résidente et s'exécute pendant un certain temps; -server "active" le JIT/HotSpot, et cela doit avoir de nombreux passages par le même chemin pour être activé. -serveur, d'autre part, ralentit exécution initiale de la JVM, car il y a plus de temps de configuration.

Il y a plusieurs bons livres et sites Web autour. Voir, par exemple, http://www.javaperformancetuning.com/

 17
Author: Charlie Martin, 2013-10-09 07:21:08

Avant-propos

Contexte

Été dans un magasin Java. Des mois entiers consacrés à l'exécution de tests de performance sur des systèmes distribués, les principales applications étant en Java. Dont certains impliquant des produits développés et vendus par Sun eux-mêmes (puis Oracle).

Je vais passer en revue les leçons que j'ai apprises, un peu d'histoire sur la JVM, quelques discussions sur les internes, quelques paramètres expliqués et enfin quelques réglages. Essayer de le garder au point afin que vous puissiez l'appliquer dans pratique.

Les choses changent rapidement dans le monde Java, donc une partie de celui-ci est peut-être déjà obsolète depuis la dernière année où j'ai fait tout cela. (Java 10 est-il déjà sorti?)

Bonnes pratiques

Ce que vous devez faire: benchmark, Benchmark, BENCHMARK!

Lorsque vous avez vraiment besoin de connaître les performances, vous devez effectuer de vrais benchmarks, spécifiques à votre charge de travail. Il n'y a pas de solution de rechange.

Aussi, vous devriez surveiller la JVM. En permettre le suivi. Le les bonnes applications fournissent généralement une page Web de surveillance et / ou une API. Sinon, il y a l'outillage Java commun (JVisualVM, JMX, hprof et certains drapeaux JVM).

Sachez qu'il n'y a généralement aucune performance à gagner en ajustant la JVM. C'est plus un "planter ou ne pas planter, trouver le point de transition". Il faut savoir que lorsque vous donnez que montant des ressources de votre application, vous pouvez toujours attendre que montant de performances en retour. La connaissance est le pouvoir.

Les performances sont principalement dictées par votre application. Si vous voulez plus vite, vous devez écrire un meilleur code.

Ce que vous ferez la plupart du temps: Vivre avec des valeurs par défaut sensibles fiables

Nous n'avons pas le temps d'optimiser et d'ajuster chaque application. La plupart du temps, nous vivrons simplement avec des valeurs par défaut sensibles.

La première chose à faire lors de la configuration d'une nouvelle application est de lire le documentation. La plupart des applications sérieuses sont livrées avec un guide pour le réglage des performances, y compris des conseils sur les paramètres JVM.

Ensuite, vous pouvez configurer l'application: JAVA_OPTS: -server -Xms???g -Xmx???g

  • -server: activer les optimisations complètes (cet indicateur est automatique sur la plupart des JVM de nos jours)
  • -Xms -Xmx: définissez le tas minimum et maximum (toujours la même valeur pour les deux, c'est à peu près les seules optimisations à faire).

Bien fait, vous connaissez tous l'optimisation paramètres il y a à connaître sur la JVM, félicitations!{[24] } C'était simple: D

Ce que tu NE FERAS JAMAIS:

Veuillez ne PAS copier la chaîne aléatoire que vous avez trouvée sur Internet, surtout quand ils prennent plusieurs lignes comme ça:

-server  -Xms1g -Xmx1g  -XX:PermSize=1g -XX:MaxPermSize=256m  -Xmn256m -Xss64k  -XX:SurvivorRatio=30  -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled  -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=10  -XX:+ScavengeBeforeFullGC -XX:+CMSScavengeBeforeRemark  -XX:+PrintGCDateStamps -verbose:gc -XX:+PrintGCDetails -Dsun.net.inetaddr.ttl=5  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=`date`.hprof   -Dcom.sun.management.jmxremote.port=5616 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -server -Xms2g -Xmx2g -XX:MaxPermSize=256m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC

Par exemple, cette chose trouvée sur la première page de Google est tout simplement terrible. Il y a des arguments spécifiés plusieurs fois avec des valeurs contradictoires. Certains forcent simplement les valeurs par défaut de la JVM (éventuellement les valeurs par défaut de 2 JVM versions en arrière). Quelques-uns sont obsolètes et simplement ignorés. Et finalement, au moins un paramètre est si invalide qu'il plantera systématiquement la JVM au démarrage par sa simple existence.

Réglage réel

Comment choisir la taille de la mémoire:

Lisez le guide de votre demande, il devrait donner une indication. Surveillez la production et ajustez ensuite. Effectuez des benchmarks si vous avez besoin de précision.

Note importante : Le processus java prendra jusqu'à tas maximum PLUS 10% . Les frais généraux X % étant la gestion du tas, non inclus dans le tas lui-même.

Toute la mémoire est généralement préallouée par le processus au démarrage. Vous pouvez voir le processus en utilisant max tas TOUT LE TEMPS. Il est tout simplement pas vrai. Vous devez utiliser les outils de surveillance Java pour voir ce qui est vraiment utilisé.

Trouver la bonne taille:

  • S'il se bloque avec OutOfMemoryException, il n'y a pas assez de mémoire
  • S'il ne plante pas avec OutOfMemoryException, c'est trop de mémoire
  • Si c'est trop de mémoire MAIS que le matériel l'a obtenu et / ou est déjà payé, c'est le numéro parfait, travail fait!

JVM6 est en bronze, JVM7 est en or, JVM8 est en platine...

La JVM s'améliore constamment. La collecte des ordures est une chose très complexe et il y a beaucoup de gens très intelligents qui y travaillent. Il avait d'énormes améliorations dans la dernière décennie, et il continuera de le faire.

Pour à vocation informative. Ils sont au moins 4 Garbage Collectors disponibles dans Oracle Java 7-8 (HotSpot) et OpenJDK 7-8. (D'autres JVM peuvent être entièrement différentes, par exemple Android, IBM, embedded):

  • SerialGC
  • ParallelGC
  • ConcurrentMarkSweepGC
  • G1GC
  • (plus les variantes et les paramètres)

[À partir de Java 7 et en avant. Le code Oracle et OpenJDK sont partiellement partagés. Le GC devrait être (principalement) le même sur les deux plate.]

JVM >= 7 ont de nombreuses optimisations et choisissent des valeurs par défaut décentes. Cela change un peu par plate-forme. Il équilibre plusieurs choses. Par exemple, décider d'activer les optimisations multicœur ou non si le processeur a plusieurs cœurs. Tu devrais le laisser faire. Ne pas modifier ou forcer les paramètres GC.

Il est correct de laisser l'ordinateur prendre la décision pour vous (c'est à cela que servent les ordinateurs). Il est préférable que les paramètres de la JVM soient optimaux à 95% tout le temps que de forcer un "toujours 8 core collection agressive pour les temps de pause inférieurs" sur toutes les boîtes, la moitié d'entre eux étant t2.petit à la fin.

Exception : Lorsque l'application est livrée avec un guide de performance et un réglage spécifique en place. Il est parfaitement correct de laisser les paramètres fournis tels quels.

Astuce : Passer à une JVM plus récente pour bénéficier des dernières améliorations peut parfois fournir un bon coup de pouce sans trop d'effort.

Cas particulier: - XX: + UseCompressedOops

La JVM a un paramètre spécial qui force l'utilisation de l'index 32bits en interne (read: pointers-like). Cela permet d'adresser 4 294 967 295 objets * 8 octets d'adresse => 32 Go de mémoire. (À NE pas confondre avec l'espace d'adressage de 4 Go pour les pointeurs RÉELS).

Il réduit la consommation globale de mémoire avec un impact positif potentiel sur tous les niveaux de mise en cache.

Exemple de la vie réelle: La documentation ElasticSearch indique qu'un 32 Go 32 Bits en cours d'exécution le nœud peut être équivalent à un nœud de 40 Go 64 bits en termes de données réelles conservées en mémoire.

Une note sur l'histoire: Le drapeau était connu pour être instable dans l'ère pré-java-7 (peut-être même pré-java-6). Cela fonctionne parfaitement dans la JVM plus récente depuis un certain temps.

Amélioration des performances de la Machine virtuelle Java HotSpot™

[...] Dans Java SE 7, l'utilisation de oops compressés est la valeur par défaut pour les processus JVM 64 bits lorsque -Xmx n'est pas spécifié et pour les valeurs de-Xmx moins de 32 gigaoctets. Pour JDK 6 avant la version 6u23, utilisez l'indicateur-XX:+UseCompressedOops avec la commande java pour activer la fonctionnalité.

Voir: Encore une fois, la JVM a des années d'avance sur le réglage manuel. Pourtant, il est intéressant de le savoir=)

Cas particulier: - XX: + UseNUMA

Non-uniform memory access (NUMA) est une conception de mémoire d'ordinateur utilisée dans le multitraitement, le temps d'accès à la mémoire dépend de l'emplacement de la mémoire par rapport à processeur. Source: Wikipedia

Les systèmes modernes ont des architectures de mémoire extrêmement complexes avec plusieurs couches de mémoire et de caches, privées et partagées, entre les cœurs et le processeur.

Il est évident que l'accès à une donnée dans le cache L2 du processeur actuel est BEAUCOUP plus rapide que de devoir aller jusqu'à une clé usb à partir d'un autre socket.

Je crois que tous les systèmes multi - socket vendus aujourd'hui sont de conception NUMA, tandis que tous les systèmes des consommateurs ne le sont PAS. Vérifiez si votre serveur prend en charge NUMA avec la commande numactl --show sous linux.

L'indicateur NUMA-aware indique à la JVM d'optimiser les allocations de mémoire pour la topologie matérielle sous-jacente.

L'augmentation des performances peut être substantielle (c'est-à-dire deux chiffres: +XX%). En fait, quelqu'un qui passe d'un "NOT-NUMA 10CPU 100GB" à un "NUMA 40CPU 400GB" pourrait subir une perte [dramatique] de performances s'il ne connaît pas le drapeau.

Note: Il y a des discussions pour détecter NUMA et définir l'indicateur automatiquement dans la JVM http://openjdk.java.net/jeps/163

Bonus: Toutes les applications ayant l'intention de s'exécuter sur du gros matériel (c'est-à-dire NUMA) doivent être optimisées pour cela. Il n'est pas spécifique aux applications Java.

Vers l'avenir: - XX: + UseG1GC

La dernière amélioration de la collecte des ordures est le G1 collector (lire: Garbage First).

Il est destiné aux cœurs élevés, systèmes à mémoire élevée. Au minimum absolu 4 cœurs + 6 Go de mémoire. Il est destiné aux bases de données et aux applications gourmandes en mémoire utilisant 10 fois plus et au-delà.

Version courte, à ces tailles, le GC traditionnel est confronté à trop de données à traiter à la fois et les pauses deviennent incontrôlables. Le G1 divise le tas en de nombreuses petites sections qui peuvent être gérées indépendamment et en parallèle pendant l'exécution de l'application.

La première version a été disponible en 2013. Il est assez mature pour la production maintenant, mais il ne sera pas aller par défaut de sitôt. Qui vaut la peine d'essayer pour les grandes applications.

Ne touchez pas: Tailles de génération (NewGen, PermGen...)

Le GC divise la mémoire en plusieurs sections. (Ne pas entrer dans les détails, vous pouvez google "Java GC Generations".)

La dernière fois que j'ai passé une semaine à essayer 20 combinaisons différentes de drapeaux de générations sur une application prenant 10000 hit / s. Je recevais un magnifique coup de pouce allant de -1% à +1%.

Les générations Java GC sont un sujet intéressant à lire ou à écrire. Ils ne sont pas une chose à régler à moins que vous ne fassiez partie du 1% qui peut consacrer un temps substantiel pour des gains négligeables parmi le 1% des personnes qui ont vraiment besoin d'optimisations.

Conclusion

J'Espère que cela peut vous aider. Amusez-vous avec la JVM.

Java est le meilleur langage et la meilleure plate-forme au monde! Allez répandre l'amour: D

 19
Author: user5994461, 2016-05-25 22:20:10

Regardez ici (ou faites une recherche Google pour hotspot tuning) http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html

Vous voulez certainement profiler votre application avant d'essayer de régler la machine virtuelle. NetBeans a un bon profileur intégré qui vous permettra de voir toutes sortes de choses.

Une fois, quelqu'un m'a dit que le GC était cassé pour leur application - j'ai regardé le code et j'ai constaté qu'ils n'avaient jamais fermé aucun de leurs résultats de requête de base de données, donc ils conservaient quantités massives de tableaux d'octets. Une fois que nous avons fermé les résultats, le temps est passé de plus de 20 minutes et un Go de mémoire à environ 2 minutes et une très petite quantité de mémoire. Ils ont pu supprimer les paramètres de réglage de la JVM et les choses étaient heureuses.

 7
Author: TofuBeer, 2009-02-19 05:54:27

Je vous suggère de profiler votre application avec l'échantillonnage du processeur et la surveillance de l'allocation des objets activés en même temps. Vous trouverez que vous obtenez des résultats très différents qui peuvent être utiles pour régler votre code. Essayez également d'utiliser le profileur hprof intégré, il peut également donner des résultats très différents.

En général, le profilage de votre application fait beaucoup plus de différence que les arguments JVM.

 1
Author: Peter Lawrey, 2009-02-19 22:48:04

La meilleure façon absolue d'y répondre est d'effectuer des tests contrôlés sur l'application dans un environnement de "production" aussi proche que possible. Il est tout à fait possible que l'utilisation de-server, une taille de tas de départ raisonnable et le comportement relativement intelligent des JVM récentes se comportent aussi bien ou mieux que la grande majorité des paramètres que l'on essaierait normalement.

Il existe une exception spécifique à cette large généralisation: dans le cas où vous exécutez dans un conteneur Web, il y a de très fortes chances que vous souhaitiez augmenter les paramètres de génération permanents.

 1
Author: , 2009-02-21 10:22:43

Java sur la machine windows 32 bits, vos choix sont limités. D'après mon expérience, le paramètre follow aura un impact sur les performances de l'application:

  1. tailles de mémoire
  2. choix des collecteurs GC
  3. paramètres liés aux collecteurs GC
 1
Author: stones333, 2012-10-15 23:07:14

Cela dépendra fortement de votre application et du fournisseur et de la version de la JVM. Vous devez être clair sur ce que vous considérez comme un problème de performance. Êtes-vous préoccupé par certaines sections critiques du code? Avez-vous présenté les app encore? La JVM passe-t-elle trop de temps à collecter les ordures?

Je commencerais probablement par l'option-verbose:gc JVM pour regarder comment fonctionne la collecte des ordures. Plusieurs fois, la solution la plus simple pour simplement augmenter la taille maximale du tas avec - Xmx . Si vous apprenez à interpréter la sortie-verbose:gc, elle vous dira presque tout ce que vous devez savoir sur le réglage de la JVM dans son ensemble. Mais faire cela seul ne fera pas comme par magie que le code mal réglé ira plus vite. La plupart des options de réglage JVM sont conçues pour améliorer les performances du garbage collector et/ou des tailles de mémoire.

Pour le profilage, j'aime yourkit.com

 0
Author: Gary, 2009-02-19 05:38:31