Étant donné que Java 7 va utiliser le nouveau garbage collection G1 par défaut est Java va être capable de gérer un tas de plus grande taille sans supposer "dévastateur") "Temps de pause GC? Quelqu'un at-il réellement mis en œuvre G1 en production, quelles ont été vos expériences?
Pour être juste, la seule fois où j'ai vu de très longues pauses GC est sur de très gros tas, bien plus qu'un poste de travail. Pour clarifier ma question; G1 ouvrira-t-il la porte d'entrée à des centaines de Go? TB?
On dirait que le point de G1 est d'avoir des temps de pause plus petits, même au point où il a la possibilité de spécifier un objectif de temps de pause maximum.
La collecte des ordures n'est pas seulement un simple problème "Hé, c'est complet, bougeons tout à la fois et recommençons" - c'est un système fileté d'arrière-plan incroyablement complexe, à plusieurs niveaux. Il peut effectuer une grande partie de sa maintenance en arrière-plan sans aucune pause, et il utilise également la connaissance des modèles attendus du système au moment de l'exécution pour aider - comme en supposant que la plupart des objets meurent juste après leur création, etc.
Je dirais que les temps de pause du GC vont continuer à s'améliorer, pas à s'aggraver, avec les prochaines versions.
MODIFIER:
en relisant, il m'est venu à l'esprit que j'utilise Java quotidiennement - Eclipse, Azureus et les applications que je développe, et cela fait LONGTEMPS depuis que j'ai vu une pause. Pas une pause significative , mais je veux dire toute pause.
J'ai vu des pauses lorsque je clique avec le bouton droit de la souris sur l'Explorateur Windows ou (parfois) lorsque je connecte certains périphériques USB, mais avec Java --- aucun.
GC est-il toujours un problème avec quelqu'un?
Je l'ai testé avec une application lourde: 60 à 70 Go alloués au tas, avec 20 à 50 Go en cours d'utilisation à tout moment. Avec ce genre d'applications, c'est un euphémisme de dire que votre kilométrage peut varier. J'utilise JDK 1.6_22 sous Linux. Les versions mineures sont importantes - avant environ 1.6_20, il y avait des bogues dans G1 qui provoquaient des NullPointerExceptions aléatoires.
J'ai trouvé qu'il est très bon de respecter la cible de pause que vous lui donnez la plupart du temps. La valeur par défaut semble être une pause de 100 ms (0,1 seconde), et je lui ai dit d'en faire la moitié (-XX: MaxGCPauseMillis = 50). Cependant, une fois qu'il manque vraiment de mémoire, il panique et effectue un ramasse-miettes complet. Avec 65 Go, cela prend entre 30 secondes et 2 minutes. (Le nombre de processeurs ne fait probablement aucune différence; il est probablement limité par la vitesse du bus.)
Par rapport au CMS (qui n'est pas le GC par défaut du serveur, mais il devrait l'être pour les serveurs Web et autres applications en temps réel), les pauses typiques sont beaucoup plus prévisibles et peuvent être raccourcies. Jusqu'à présent, j'ai plus de chance avec CMS pour les énormes pauses, mais cela peut être aléatoire; Je ne les vois que quelques fois toutes les 24 heures. Je ne sais pas lequel sera le plus approprié dans mon environnement de production pour le moment, mais probablement G1. Si Oracle continue de le régler, je pense que G1 sera finalement le gagnant clair.
Si vous ne rencontrez pas de problème avec les récupérateurs existants, il n'y a aucune raison d'envisager G1 pour le moment. Si vous exécutez une application à faible latence, telle qu'une application GUI, G1 est probablement le bon choix, avec MaxGCPauseMillis réglé très bas. Si vous exécutez une application en mode batch, G1 ne vous achète rien.
Bien que je n'aie pas testé le G1 en production, j'ai pensé commenter que les GC sont déjà problématiques pour les cas sans tas "énormes". Plus précisément, les services avec juste, disons, 2 ou 4 concerts peuvent être gravement touchés par GC. Les GC de jeune génération ne sont généralement pas problématiques car ils se terminent en millisecondes à un chiffre (ou tout au plus à deux chiffres). Mais les collections de l'ancienne génération sont beaucoup plus problématiques car elles prennent plusieurs secondes avec des tailles d'ancienne génération de 1 gig ou plus.
Maintenant: en théorie, le CMS peut y aider beaucoup, car il peut exécuter la plupart de ses opérations simultanément. Cependant, au fil du temps, il y aura des cas où il ne pourra pas le faire et devra se replier pour "arrêter le monde". Et quand cela se produit (après, disons, 1 heure - pas souvent, mais encore trop souvent), bien, accrochez-vous à vos chapeaux. Cela peut prendre une minute ou plus. Cela est particulièrement problématique pour les services qui tentent de limiter la latence maximale; au lieu que cela prenne, disons, 25 millisecondes pour répondre à une demande, cela prend maintenant dix secondes ou plus. Pour ajouter une blessure à l'insulte, les clients expireront souvent la demande et réessayer, ce qui entraînera d'autres problèmes (alias "merde de merde").
C'est un domaine où G1 espérait beaucoup aider. J'ai travaillé pour une grande entreprise qui propose des services cloud pour le stockage et l'envoi de messages; et nous ne pouvions pas utiliser CMS car bien que la plupart du temps cela fonctionnait mieux que les variétés parallèles, il y avait ces effondrements. Donc, pendant environ une heure, les choses ont été agréables; et puis des trucs ont frappé le ventilateur ... et parce que le service était basé sur des clusters, lorsqu'un nœud a eu des problèmes, d'autres ont généralement suivi (car les délais d'attente induits par le GC conduisent à d'autres nœuds croient que le nœud s'est écrasé, conduisant à des réacheminements).
Je ne pense pas que GC soit un problème majeur pour les applications, et peut-être même que les services non groupés sont moins souvent affectés. Mais de plus en plus de systèmes sont regroupés (en particulier grâce aux magasins de données NoSQL) et les tailles de tas augmentent. Les GC OldGen sont liés de façon super-linéaire à la taille du tas (ce qui signifie que doubler la taille du tas fait plus que doubler le temps du GC, en supposant que la taille de l'ensemble de données en direct double également).
Le directeur technique d'Azul, Gil Tene, a une belle vue d'ensemble des problèmes associés à la collecte des ordures et un examen des diverses solutions dans son Comprendre Java Garbage Collection et ce que vous pouvez faire à ce sujet présentation, et il y a des détails supplémentaires dans cet article: http://www.infoq.com/articles/azul_gc_in_detail .
Le garbage collector C4 d'Azul dans notre machine virtuelle Java Zing est à la fois parallèle et simultané, et utilise le même mécanisme GC pour les générations nouvelles et anciennes, travaillant simultanément et compactant dans les deux cas. Plus important encore, C4 n'a pas de repli sur le monde. Tout le compactage est effectué simultanément avec l'application en cours d'exécution. Nous avons des clients exécutant de très grandes tailles (des centaines de Go) avec des pires temps de pause du GC <10 ms, et en fonction de l'application, souvent moins de 1 à 2 ms.
Le problème avec CMS et G1 est qu'à un certain point Java doit être compactée, et ces deux garbage collectors arrêtent le monde/STW (c'est-à-dire mettent en pause l'application) pour effectuer le compactage. Ainsi, bien que CMS et G1 puissent éliminer les pauses STW, ils ne les éliminent pas.Cependant, le C4 d'Azul élimine complètement les pauses STW et c'est pourquoi Zing a des pauses GC aussi faibles même pour des tailles de tas gigantesques.
Et pour corriger une déclaration faite dans une réponse antérieure, Zing ne nécessite aucune modification du système d'exploitation. Il fonctionne comme n'importe quelle autre machine virtuelle Java sur des distributions Linux non modifiées.
Nous utilisons déjà G1GC depuis presque deux ans. Il fonctionne très bien dans notre système de traitement des transactions critiques, et il s'est avéré être un excellent support avec un débit élevé, des pauses faibles, des accès simultanés et une gestion optimisée de la mémoire lourde.
Nous utilisons les paramètres JVM suivants:
-server -Xms512m -Xmx3076m -XX:NewRatio=50 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000 -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime
mis à jour
-d64 -server -Xss4m -Xms1024m -Xmx4096m -XX:NewRatio=50 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:-DisableExplicitGC -XX:+AggressiveOpts -Xnoclassgc -XX:+UseNUMA -XX:+UseFastAccessorMethods -XX:ReservedCodeCacheSize=48m -XX:+UseStringCache -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000
Le collecteur G1 réduit l'impact des collections complètes. Si vous avez une application où vous avez déjà réduit le besoin de collections complètes, le collecteur de balayage de carte simultané est tout aussi bon et selon mon expérience, les temps de collecte mineurs sont plus courts.
Il semble que G1 démarrant JDK7u4 soit finalement officiellement pris en charge, voir le RN pour JDK7u4 http://www.Oracle.com/technetwork/Java/javase/7u4-relnotes-1575007.html .
D'après nos tests, toujours pour les grosses JVM, le CMS réglé agit toujours mieux que G1, mais je suppose qu'il se développera mieux.
Je viens d'implémenter G1 Garbage Collector dans notre projet Terracotta Big Memory. En travaillant sur différents types de collecteurs, G1 nous a donné les meilleurs résultats avec moins de 600 ms de temps de réponse.
Vous pouvez trouver les résultats des tests (26 au total) ici
J'espère que ça aide.
Récemment, j'ai déménagé de
CMS vers G1GC avec tas 4G et processeur 8 cœurs sur serveurs avec JDK 1.7.45.
(JDK 1.8.x G1GC est préféré à 1.7 mais en raison de certaines limitations, je dois m'en tenir à la version 1.7.45)
J'ai configuré les paramètres clés ci-dessous et conservé tous les autres paramètres aux valeurs par défaut.
-XX:G1HeapRegionSize=n, XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n,
-XX:ConcGCThreads=n apart from -Xms and -Xmx
Si vous souhaitez affiner ces paramètres, consultez cet article Oracle .
Observations clés:
Mais je suis toujours heureux que le temps de pause Max GC soit inférieur à celui du CMS. J'ai défini le temps de pause Max GC comme 1,5 seconde et cette valeur n'a pas encore été franchie.
Question SE associée:
Le CMS peut conduire à une dégradation lente des performances même si vous l'exécutez sans accumuler d'objets tenured. Cela est dû à la fragmentation de la mémoire que G1 évite soi-disant.
Le mythe de G1 disponible uniquement avec un support payant n'est que cela, un mythe. Sun et maintenant Oracle ont clarifié cela sur la page JDK.
G1 GC est censé fonctionner mieux. Mais si vous définissez -XX: MaxGCPauseMillis de manière trop agressive, les déchets seront collectés trop lentement. Et c'est pourquoi le GC complet s'est déclenché dans l'exemple de David Leppik.
J'ai récemment migré une partie de Twicsy vers un nouveau serveur avec 128 Go RAM et j'ai décidé d'utiliser 1.7. J'ai commencé à utiliser tous les mêmes paramètres de mémoire que j'utilisais avec 1.6 (j'ai plusieurs instances en cours d'exécution faisant diverses choses, allant de 500 Mo de tas à 15 Go, et maintenant un nouveau avec 40 Go) et cela n'a pas bien fonctionné du tout. 1.7 semble utiliser plus de tas que 1.6, et j'ai rencontré beaucoup de problèmes au cours des premières jours. Heureusement, j'ai eu beaucoup de RAM pour travailler avec et augmenté le RAM pour la plupart de mes processus, mais j'ai toujours eu quelques problèmes. Mon MO normal était d'utiliser une très petite taille de segment de mémoire minimale de 16 m, même avec un segment de mémoire maximal de plusieurs gigaoctets, puis d'activer le GC incrémentiel. Cela a maintenu les pauses au minimum. Cela ne fonctionne pas maintenant cependant, et j'ai dû augmenter le minimum taille à peu près à ce que je pensais utiliser en moyenne dans le tas, et cela a très bien fonctionné. J'ai toujours le GC incrémentiel activé, mais je vais l'essayer sans. Aucune pause que ce soit maintenant, et les choses semblent fonctionner très vite. Donc, je pense que la morale de l'histoire est de ne pas s'attendre à ce que vos paramètres de mémoire se traduisent parfaitement de 1,6 à 1,7.
G1 rend l'application beaucoup plus agile: la latence de l'application augmentera - l'application peut être nommée "soft-real-time". Cela se fait en remplaçant deux types de tirages GC (petits petits et un grand sur Tenured Gen) par des petits de taille égale.
Pour plus de détails, regardez ceci: http://geekroom.de/Java/java-expertise-g1-fur-Java-7/
J'utilise G1GC sur Java 8 et aussi avec Groovy (aussi Java 8), et je fais différents types de charges de travail, et globalement G1GC fonctionne comme ceci:
L'utilisation de la mémoire est très faible, par ex. 100 Mo au lieu de 500 Mo par rapport aux paramètres par défaut Java settings
Le temps de réponse est constant et très faible
Les performances entre les paramètres par défaut et G1GC sont de 20% de ralentissement lors de l'utilisation de G1GC dans le pire des cas (sans réglage, application à un seul thread). Ce n'est pas beaucoup compte tenu du bon temps de réponse et de la faible utilisation de la mémoire.
Lors de l'exécution à partir de Tomcat qui est multi-thread, les performances globales sont 30% meilleures et l'utilisation de la mémoire est beaucoup plus faible ainsi que les temps de réponse sont beaucoup plus faibles.
Donc, dans l'ensemble, lors de l'utilisation de charges de travail très diverses, G1GC est un très bon collecteur pour Java 8 pour les applications multithreads, et même pour les threads simples, il y a certains avantages.
Je travaille avec Java, pour les petits et les grands tas, et la question du GC et du GC complet apparaît chaque jour, car les contraintes peuvent être plus strictes que d'autres: dans certains environnements, 0,1 seconde de GC récupérateur ou GC complet, tuez simplement la fonctionnalité, et avoir une configuration et des capacités à grain fin est important (CMS, iCMS, autres ... la cible est ici d'avoir le meilleur temps de réponse possible avec le traitement en temps quasi réel (ici le traitement en temps réel est souvent de 25 ms)) , donc, fondamentalement, toute amélioration de l'ergonomie et de l'heuristique GC est la bienvenue!
Il n'est pas suggéré d'utiliser Java8 avec G1GC pour le calcul du point flottant avec une JVM de type hotspot. C'est dangereux pour l'intégrité et la précision des applications.
https://bugs.openjdk.Java.net/browse/JDK-8148175
JDK-8165766
JDK-8186112