Récupération de la mémoire Java G1 en production


91

Puisque Java 7 va utiliser le nouveau garbage collection G1 par défaut, Java sera-t-il capable de gérer un tas plus grand d'un ordre de grandeur sans temps de pause GC "dévastateurs" supposés? Quelqu'un a-t-il réellement mis en œuvre G1 en production, quelles ont été vos expériences?

Pour être honnête, la seule fois où j'ai vu de très longues pauses GC, c'est sur de très gros tas, bien plus qu'un poste de travail n'en aurait. Pour clarifier ma question; G1 ouvrira-t-il la porte à des tas de centaines de Go? TB?


15
Bien que cela puisse être reformulé plus spécifiquement, ce n'est pas une question horrible. J'aurais vraiment aimé que les gens s'expliquent mieux que "Pas une question" lors du vote pour clôturer.
Bill K

Je n'ai pas voté pour la fermeture, mais j'aurais souhaité que l'OP fasse un travail plus objectif en détaillant ses griefs avec le GC actuel. Aussi, "Java" est un langage alors qu'il parle d'une implémentation, et je ne sais pas ce que signifie "implémenter G1 en production", surtout avec le futur du reste de la question. Si cela doit être en Java 7, personne ne l'a sûrement utilisé en production?
Pascal Cuoq

6
@Pascal G1 est une fonctionnalité expérimentale disponible dans le JDK depuis la mise à jour 14 du JDK 6. En "implémentant G1 en production", je pense qu'il voulait dire l'utiliser réellement, ce n'est pas si difficile à comprendre. Et bien que je convienne que G1 fait partie de JDK 7, pas de Java, une recherche de Java 7 sur Google renvoie la page d'accueil du JDK 7 comme premier résultat, et les deux termes sont souvent utilisés de manière interchangeable. @Benju Je ne ferais pas confiance aux résultats obtenus avec G1 sur le JDK actuel car il est expérimental, beaucoup de choses pourraient changer d'ici la sortie officielle.
teto

2
Il semble que JDK 7, y compris les mises à jour 1, 2 et 3 n'utilise pas le G1 gc par défaut. Vous pouvez le voir par jinfo -flag UseG1GC pid
George

Réponses:


34

On dirait que le but 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 maximal.

Le ramassage des ordures n'est plus simplement une simple affaire «Hé, c'est plein, déplaçons tout en même temps et recommençons» - c'est un système de threads en 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 supposer que la plupart des objets meurent juste après avoir été créés, etc.

Je dirais que les temps de pause du GC vont continuer à s'améliorer, et non à empirer, avec les prochaines versions.

ÉDITER:

en relisant, il m'est venu à l'esprit que j'utilise quotidiennement Java - Eclipse, Azureus et les applications que je développe, et cela fait LONGTEMPS que je n'ai pas vu une pause. Pas une pause significative, mais je veux dire une pause du tout.

J'ai vu des pauses lorsque je clique avec le bouton droit de la souris sur l'explorateur Windows ou (occasionnellement) lorsque je connecte certains matériels USB, mais avec Java - rien du tout.

GC est-il toujours un problème avec quelqu'un?


D'accord - la seule fois où j'ai vu des pauses GC, c'est lorsque je les ai provoquées délibérément ou accidentellement avec un code de création de déchets massivement parallèle .....
mikera

28
Oui, GC est toujours très problématique lorsque vous commencez à gérer de gros tas (> 16 Go), en particulier avec de grandes générations titulaires.
The Alchemist

2
@ the-alchemist wow, j'ai vu ton commentaire au passage à quelques reprises et ça m'a frappé que tu disais 16 Go !! Bien que je sois absolument sûr que vous avez raison, cela peut entraîner d'énormes retards, je veux vérifier que vous avez désactivé TOUS les échanges. Sur un système à grande mémoire, tout échange de java tuera absolument votre système (car GC est très hostile aux échanges). Je suis sûr que vous l'avez déjà fait, mais je voulais juste le mentionner - parce que cela ferait une énorme différence. Je n'ai jamais vu un PC avec autant de RAM - combien en avez-vous? 32g?
Bill K

8
Oui, les CG sont problématiques pour les services en ce sens qu'ils sont ce qui rend TRÈS difficile l'amélioration des limites TP99.9 (et supérieures). Plus précisément, les GC de «l'ancienne génération» peuvent être des pièges mortels qui gèlent pratiquement la JVM (et le service) pendant plusieurs secondes; et pour les services qui répondent généralement aux demandes en millisecondes à un chiffre (ou à deux chiffres), cela pose problème. Pour ce que cela vaut, c'était un problème pratique avec le stockage backend utilisé par le service Simple Queue d'Amazon (ne peut pas entrer dans des tonnes de détails car il est interne à AWS).
StaxMan

21
Ce qui est ennuyeux à propos de GC, c'est qu'Azul a inventé il y a des années un ingénieux algorithme GC (Azul C4) qui peut facilement faire face à des centaines de gigaoctets sans temps de pause notable en utilisant très intelligemment le matériel de mémoire du processeur. Mais personne ne le sait et il ne sera bientôt pas implémenté dans les principales versions de Java car il a besoin d'un support de la part du système d'exploitation. Et les fournisseurs de systèmes d'exploitation ne feront rien tant que les gens ne connaîtront pas l'algorithme et ne feront pas pression sur les fournisseurs de systèmes d'exploitation. Voir azulsystems.com/zing/pgc , managedruntime.org
Hans-Peter Störr

58

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 type d'applications, c'est peu dire que votre kilométrage peut varier. J'exécute JDK 1.6_22 sur 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 efficace pour respecter l'objectif 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 garbage collection complet. Avec 65 Go, cela prend entre 30 secondes et 2 minutes. (Le nombre de processeurs ne fait probablement pas de différence; il est probablement limité par la vitesse du bus.)

Par rapport au CMS (qui n'est pas le serveur GC par défaut, 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 beaucoup plus courtes. 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 soupçonne que G1 sera finalement le gagnant clair.

Si vous n'avez pas de problème avec les garbage collors 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.


14

Bien que je n'ai pas testé G1 en production, j'ai pensé que je dirais que les GC sont déjà problématiques pour les cas sans tas "énormes". Plus précisément, les services avec seulement, disons, 2 ou 4 concerts peuvent être gravement touchés par GC. Les GC de la jeune génération ne posent généralement pas de problème car ils se terminent en millisecondes à un chiffre (ou au plus à deux chiffres). Mais les collections d'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 beaucoup y aider, car il peut exécuter la plupart de ses opérations simultanément. Cependant, avec le temps, il y aura des cas où il ne pourra pas le faire et devra se rabattre sur la collection «stop the world». Et quand cela se produit (après, disons, 1 heure - pas souvent, mais encore trop souvent), eh bien, gardez vos putains de chapeaux. Cela peut prendre une minute ou plus. Ceci est particulièrement problématique pour les services qui tentent de limiter la latence maximale; au lieu de prendre, disons, 25 millisecondes pour traiter une demande, il faut maintenant dix secondes ou plus. Pour ajouter une blessure à l'insulte, les clients expireront souvent la demande et réessayeront, ce qui entraînera d'autres problèmes (alias "shit storm").

C'est un domaine dans lequel 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 étaient bien; et puis les choses ont frappé le ventilateur ... et parce que le service était basé sur des clusters, quand un nœud a eu des problèmes, d'autres ont généralement suivi (puisque les délais induits par GC conduisent d'autres nœuds à croire que le nœud s'est écrasé, conduisant à des réacheminements).

Je ne pense pas que GC soit un problème pour les applications, et peut-être que même 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 la taille des tas augmente. Les GC OldGen sont super-linéairement liés à la taille du tas (ce qui signifie que doubler la taille du tas fait plus que doubler le temps GC, en supposant que la taille de l'ensemble de données en direct double également).


13

Le CTO d'Azul, Gil Tene, a un bon aperçu des problèmes associés à la récupération de place et un examen de diverses solutions dans sa présentation Comprendre la récupération de place Java et ce que vous pouvez faire à ce sujet , 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 JVM Zing est à la fois parallèle et simultané et utilise le même mécanisme GC pour les nouvelles et anciennes générations, fonctionnant simultanément et compactant dans les deux cas. Plus important encore, C4 n'a pas de solution de secours pour arrêter le monde. Tout le compactage est effectué en même temps que l'application en cours d'exécution. Nous avons des clients exécutant de très gros volumes (des centaines de Go) avec des temps de pause GC dans le pire des cas <10 msec, et selon l'application, souvent moins de 1 à 2 msec.

Le problème avec CMS et G1 est qu'à un moment donné, la mémoire de tas Java doit être compactée, et ces deux garbage collector stop-the-world / STW (c'est-à-dire interrompent l'application) pour effectuer le compactage. Ainsi, bien que CMS et G1 puissent supprimer 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 précédente, 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.


3
Je me demande simplement comment le C4 d'Azul a réalisé ce que vous avez dit et pourquoi Sun ou Oracle ne le peuvent pas. Y a-t-il un grand secret ou est-ce juste une sorte de compromis?
George

5
Le C4 d'Azul possède une technologie très unique qui a ses origines dans les appliances de calcul matérielles d'Azul (qui utilisent des processeurs spécialisés conçus pour exécuter des applications Java d'entreprise) et a été évoluée pour fonctionner sur des serveurs x86 normaux exécutant Linux. Chaque autre garbage collector de classe entreprise (qu'il soit d'Oracle ou d'IBM) doit à un moment donné faire des pauses d'arrêt du monde - l'attribut unique du C4 d'Azul est qu'il ne fait jamais ces pauses STW problématiques. Si vous êtes curieux, les inventeurs du collectionneur C4 ont publié un article expliquant son fonctionnement: dl.acm.org/citation.cfm?id=1064988 .
Scott Sellers

Scott, j'ai lu ici blog.mikemccandless.com/2012/07/… qu'Azul livre un module de noyau qui pré-alloue de la mémoire pour l'utilisation de la JVM. N'est-ce pas vrai? Si c'est vrai, pas beaucoup de modification du noyau mais toujours une modification.
Dan Pritts

4
George, deux mots: brevet protégé. Dan, lorsque vous achetez Zing, vous payez une partie de ce que vous payez, c'est que le personnel d'assistance l'adapte à votre application - et cela inclut l'allocation de l'utilisation globale de la mémoire système. Le module du noyau lui-même empêche les écritures dans un bloc de mémoire en cours de récupération de place. C'est la sauce secrète qui le rend "sans pause": les threads ne s'arrêtent que s'ils essaient d'écrire dans l'un de ces blocs, et seulement assez longtemps pour compacter ce bloc.
David Leppik

13

Nous utilisons déjà G1GC, depuis près de 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 pour un débit élevé, de faibles pauses, une concurrence 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

Actualisé

-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

5
Dans Java 8, vous n'avez pas besoin de définir -XX: + UseCompressedOops ou -XX: + DoEscapeAnalysis, les cabines sont activées par défaut. Voir: docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
Mirko Ebert

8

Le collecteur G1 réduit l'impact des collections complètes. Si vous avez une application dans laquelle vous avez déjà réduit le besoin de collections complètes, le collecteur Concurrent map Sweep est tout aussi bon et, d'après mon expérience, il a des temps de collecte mineurs plus courts.


"Notez que l'utilisation de G1 en production n'est autorisée que lorsqu'un contrat de support Java a été acheté.", groups.google.com/forum/#!topic/javaposse/Vm0a4H-QY54 , c'est donc un mythe ou pas?
Christophe Roussy le

1
@ChristopheRoussy Je ne sais pas si cela est vrai plus (ou en fait la preuve que cela a jamais été vrai) Il ne nécessite pas le -XX: + UnlockCommercialFeatures donc je soupçonne que G1 ne nécessite pas de licence.
Peter Lawrey


5

Récemment, j'ai été déplacé de

CMS vers G1GC avec tas 4G et processeur 8 cœurs sur les 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é ci-dessous les paramètres clés et gardé 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 sur oracle .

Principales observations:

  1. L'utilisation de la mémoire est cohérente avec G1GC contrairement aux hauts et bas avec CMS
  2. Le temps de pause maximal du GC est inférieur à celui du CMS
  3. Le temps passé dans le garbage collection est un peu élevé dans G1GC par rapport au CMS.
  4. Le nombre de collections majeures est presque négligeable par rapport à CMS
  5. Le nombre de collections mineures est supérieur à celui du CMS

Mais je suis toujours heureux que le temps de pause Max GC soit inférieur à celui de CMS. J'ai défini le temps de pause Max GC à 1,5 seconde et cette valeur n'a pas encore été franchie.

Question SE connexe:

Récupération de la mémoire Java 7 (JDK 7) et documentation sur G1


4

CMS peut entraîner une dégradation lente des performances, même si vous l'exécutez sans accumuler d'objets permanents. Ceci est dû à la fragmentation de la mémoire que G1 est censée éviter.

Le mythe sur G1 disponible uniquement avec un support payant n'est que cela, un mythe. Sun et maintenant Oracle ont clarifié cela sur la page JDK.


4

G1 GC est censé fonctionner mieux. Mais si le réglage -XX: MaxGCPauseMill est trop agressif, 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.


4

Je viens d'implémenter G1 Garbage Collector dans notre projet Terracotta Big Memory. Tout en travaillant sur différents types de collecteurs, G1 nous a donné les meilleurs résultats avec un temps de réponse inférieur à 600 ms.

Vous pouvez trouver les résultats des tests (26 au total) ici

J'espère que ça aide.


3

J'ai récemment migré une partie de Twicsy vers un nouveau serveur avec 128 Go de RAM et j'ai décidé d'utiliser 1.7. J'ai commencé par utiliser tous les mêmes paramètres de mémoire que ceux que j'utilisais avec 1.6 (j'ai plusieurs instances en cours d'exécution pour faire diverses choses, de 500 Mo de tas à 15 Go, et maintenant une nouvelle 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 premiers jours. Heureusement, j'avais beaucoup de RAM pour travailler et j'ai augmenté la RAM pour la plupart de mes processus, mais j'avais encore des problèmes. Mon MO normal était d'utiliser une très petite taille de tas minimum de 16 m, même avec un tas maximum de plusieurs gigaoctets, puis d'activer le GC incrémentiel. Cela a réduit les pauses au minimum. Cela ne fonctionne pas maintenant, et j'ai dû augmenter la taille minimale à peu près à ce que je m'attendais à utiliser en moyenne dans le tas, et cela a très bien fonctionné. Le GC incrémentiel est toujours activé, mais je vais l'essayer sans. Aucune pause pour le moment et les choses semblent aller très vite. Donc, je pense que la morale de l'histoire est de ne pas vous attendre à ce que vos paramètres de mémoire se traduisent parfaitement de 1,6 à 1,7.


2

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 d'exécutions GC (petites mineures et une grande sur Tenured Gen) par des petites de taille égale.

Pour plus de détails, consultez ceci: http://geekroom.de/java/java-expertise-g1-fur-java-7/


1

Je travaille avec Java, pour petits et grands Heap, et la question du GC et du Full GC apparaît tous les jours, car les contraintes peuvent être plus strictes que d'autres: dans certains environnements, 0,1 seconde de scavenger GC ou Full GC, kill simplement la fonctionnalité, et avoir une configuration et une capacité à grain fin est important (CMS, iCMS, autres ... l'objectif est ici d'avoir le meilleur temps de réponse possible avec le traitement presque en temps 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 du GC est la bienvenue!


1

J'utilise G1GC sur Java 8 et aussi avec Groovy (également 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 exemple 100 Mo au lieu de 500 Mo par rapport aux paramètres Java par défaut

  • 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 monothread). Ce n'est pas grand-chose compte tenu d'un bon temps de réponse et d'une 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, lorsque vous utilisez des charges de travail vraiment diverses, G1GC est un très bon collecteur pour Java 8 pour les applications multithreads, et même pour les applications à un seul thread, il y a certains avantages.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.