web-dev-qa-db-fra.com

Java très grandes tailles de tas

Quelqu'un a-t-il déjà utilisé de très gros tas, 12 Go ou plus en Java?

  • Le GC rend-il le programme inutilisable?
  • Quels paramètres du GC utilisez-vous?
  • Quelle machine virtuelle, Sun ou BEA conviendrait mieux à cela?
  • Quelle plate-forme, Linux ou Windows, fonctionne mieux dans de telles conditions?
  • Dans le cas de Windows, existe-t-il une différence de performances entre Vista 64 bits et XP sous de telles charges de mémoire?
74
pdeva

Si votre application n'est pas interactive et que les pauses GC ne vous posent pas de problèmes, Java ne devrait pas rencontrer de problèmes pour gérer de très grands tas, même par centaines de Go. Nous n'avons pas non plus remarqué de problèmes de stabilité sous Windows ou Linux.

Cependant, lorsque vous devez limiter les pauses GC, les choses deviennent vraiment désagréables:

  1. Oubliez le débit par défaut, arrêtez le GC. Il interrompra votre application pendant plusieurs dizaines de secondes pour les tas modérés (<~ 30 Go) et plusieurs minutes pour les plus grands (> ~ 30 Go). Et acheter des DIMM plus rapidement ne vous aidera pas.

  2. Le meilleur choix est probablement le collecteur CMS, activé par -XX: + UseConcMarkSweepGC. Le ramasse-miettes CMS arrête l'application uniquement pendant la phase de marquage initiale et les phases de remarques. Pour de très petits tas comme <4 Go, cela ne pose généralement pas de problème, mais pour une application qui crée beaucoup de déchets et un grand tas, la phase de remarque peut prendre un temps assez long - généralement beaucoup moins que complet. , mais peut toujours être un problème pour les très grands tas.

  3. Lorsque le ramasse-miettes CMS n'est pas assez rapide pour terminer ses opérations avant la fin de la génération permanente, il revient au GC standard stop-the-world. Attendez-vous à des pauses d'environ 30 secondes ou plus pour les piles de 16 Go. Vous pouvez essayer d'éviter de garder le taux de production de déchets de longue durée de votre application aussi bas que possible. Notez que plus le nombre de cœurs exécutant votre application est élevé, plus le problème s'aggrave, car le CMS utilise un seul cœur. Evidemment, méfiez-vous il y a no garantie que le CMS ne fait pas appel au collecteur STW. Et lorsque cela se produit, cela se produit généralement lors des pics de charge et votre application est morte pendant plusieurs secondes. Vous ne voudrez probablement pas signer un SLA pour une telle configuration.

  4. Eh bien, il y a cette nouvelle chose G1. Il est théoriquement conçu pour éviter les problèmes avec CMS, mais nous l'avons essayé et avons observé que:

    • Son débit est pire que celui du CMS.
    • En théorie, il devrait éviter de collecter d'abord les blocs de mémoire populaires, mais il passe bientôt à un état où presque tous les blocs sont "populaires", et les hypothèses sur lesquelles il est basé cessent tout simplement de fonctionner.
    • Enfin, le repli stop-the-world existe toujours pour G1; demander à Oracle, quand ce code est censé être exécuté. S'ils disent "jamais", demandez-leur pourquoi le code est là. Donc, IMHO G1 ne fait pas disparaître le problème de l’énorme tas de Java, il le rend seulement (sans doute) un peu plus petit.
  5. Si vous avez des sous pour un gros serveur avec beaucoup de mémoire, vous avez probablement aussi aussi pour une bonne technologie de GC accélérée sans accélération, telle que celle proposée par Azul. Nous avons l'un de leurs serveurs avec 384 Go RAM et cela fonctionne vraiment bien - pas de pauses, 0 lignes de code stop-the-world sur le GC. 

  6. Ecrivez la foutue partie de votre application qui nécessite beaucoup de mémoire en C++, comme LinkedIn l’a fait avec le traitement de graphe social. Vous ne pourrez toujours pas éviter tous les problèmes en procédant ainsi (par exemple, la fragmentation de tas), mais il serait certainement plus facile de limiter les pauses.

70

Je suis le PDG d’Azul Systems et mon opinion sur ce sujet est évidemment biaisée! :) Cela étant dit...

Gil Tene, CTO d’Azul, a un bon aperçu des problèmes associés à Garbage Collection et un examen de diverses solutions dans son Présentation de Java Garbage Collection et de ce que vous pouvez faire présentation, et cet article contient des détails supplémentaires: http://www.infoq.com/articles/azul_gc_in_detail .

Le récupérateur de déchets C4 d'Azul dans notre machine virtuelle Zing est à la fois parallèle et simultané. Il utilise le même mécanisme de GC pour les générations nouvelles et anciennes, fonctionnant simultanément et compactant dans les deux cas. Plus important encore, le C4 n'a pas de repli sur le monde. Tout compactage est effectué simultanément avec l'application en cours d'exécution. Nous avons des clients très gros (des centaines de Go) avec des temps de pause GC <10 ms, dans le pire des cas. Selon l'application, ils sont souvent inférieurs à 1-2 ms.

Le problème avec CMS et G1 est qu’à un moment donné, la mémoire heap Java doit être compactée et que ces deux éboueurs arrêtent le monde/STW (c’est-à-dire mettent l’application en pause) pour effectuer le compactage. Ainsi, alors que CMS et G1 peuvent supprimer les pauses STW, ils ne les éliminent pas. Le C4 d’Azul, en revanche, élimine complètement les pauses STW et c’est pourquoi Zing a des pauses GC aussi basses, même pour des tailles de tas gigantesques.

17
Scott Sellers

Nous avons une application pour laquelle nous allouons 12-16 Go, mais elle n’atteint réellement que 8-10 en fonctionnement normal. Nous utilisons la JVM de Sun (des IBM éprouvés et ce fut un peu un désastre, mais cela aurait peut-être été une ignorance de notre part ... J'ai des amis qui jurent, qui travaillent chez IBM) Tant que vous laissez à votre application une marge de manœuvre, la machine virtuelle Java peut gérer de grandes tailles de segment de mémoire sans trop de GC. Beaucoup de mémoire supplémentaire est la clé.
Linux est presque toujours plus stable que Windows et s’il n’est pas stable, il est bien plus facile de comprendre pourquoi. Solaris est également solide et vous obtenez DTrace aussi :) Avec ce type de charge, pourquoi voudriez-vous utiliser Vista ou XP? Vous ne faites que demander des ennuis. Nous ne faisons pas de fantaisie avec les paramètres du GC. Nous définissons l’allocation minimale égale au maximum, de sorte que le système n’essaie pas constamment de le redimensionner, mais c’est tout. 

15
Ichorus

J'ai utilisé des tailles de tas supérieures à 60 Go sur deux applications différentes sous Linux et Solaris, en utilisant respectivement les versions 64 bits (évidemment) de la JVM Sun 1.6.

Je n'ai jamais rencontré de problèmes de récupération de place avec l'application Linux, sauf lorsque la limite de taille du tas était dépassée. Pour éviter les problèmes épineux inhérents à ce scénario (trop de temps consacré à la récupération de place), j'ai simplement optimisé l'utilisation de la mémoire tout au long du programme afin que l'utilisation maximale soit d'environ 5 à 10% inférieure à une limite de taille de segment de mémoire de 64 Go.

Cependant, avec une application différente fonctionnant sous Solaris, j’ai rencontré des problèmes importants de ramassage des ordures qui ont rendu nécessaire de nombreux ajustements. Cela consistait principalement en trois étapes:

  1. Activer/forcer l'utilisation du garbage collector parallèle via les options JVM -XX: + UseParallelGC -XX: + UseParallelOldGC, ainsi que le contrôle du nombre de threads GC utilisés via l'option -XX: ParallelGCThreads. Reportez-vous à la section " Paramétrage de la récupération de place pour la machine virtuelle JavaSpot 6 HotSpot " pour plus de détails.

  2. Réglage extensif et apparemment ridicule des variables locales sur "nulles" après qu’elles ne sont plus nécessaires. La plupart de ces variables auraient dû être éligibles pour la récupération de place après avoir été dépassées, et il ne s'agissait pas de fuites de mémoire, car les références n'avaient pas été copiées. Cependant, cette stratégie de «main dans la main» pour faciliter la collecte des ordures était inexplicablement nécessaire pour une raison quelconque de cette application sur la plate-forme Solaris en question.

  3. Utilisation sélective de l'appel de la méthode System.gc () dans les sections de code de clé après de longues périodes d'affectation temporaire d'objets. Je suis conscient des réserves standard relatives à l'utilisation de ces appels, ainsi que de l'argument selon lequel ils devraient normalement être inutiles, mais je les ai jugées critiques pour le contrôle de la gestion des déchets lors de l'exécution de cette application gourmande en mémoire.

Les trois étapes ci-dessus ont permis de maintenir cette application contenue et de fonctionner de manière productive avec une utilisation de 60 Go de tas au lieu de devenir hors de contrôle jusqu'à la limite de 128 Go de taille de tas qui était en place. Le ramasse-miettes en particulier s’est avéré très utile car les cycles de ramassage des ordures sont coûteux quand il y a beaucoup d’objets, c’est-à-dire que le temps requis pour le ramassage des ordures important est fonction du nombre d’objets dans le tas.

Je ne peux pas commenter d'autres problèmes spécifiques à la plate-forme à cette échelle, et je n'ai pas utilisé de JVM non-Sun (Oracle).

9
Joel Hoff

12 Go ne devrait pas poser de problème avec une implémentation JVM décente telle que le Hotspot de Sun. Je vous conseillerais d'utiliser le colllecteur Concurrent Mark and Sweep (-XX: + UseConcMarkSweepGC) lorsque vous utilisez un ordinateur virtuel Sun.Otherwies peut être confronté à de longues phases d'arrêt du monde, où tous les threads sont arrêtés pendant un GC. 

Le système d'exploitation ne devrait pas faire une grande différence pour les performances du GC. 

Vous aurez bien sûr besoin d’un système d’exploitation 64 bits et d’une machine disposant de suffisamment de RAM physique. 

8
kohlerm

Je recommande également d'envisager de réaliser un vidage de tas et de voir où l'utilisation de la mémoire peut être améliorée dans votre application et d'analyser le vidage dans un fichier tel que Eclipse's MAT . Il y a quelques articles sur la page MAT pour commencer à chercher des fuites de mémoire. Vous pouvez utiliser jmap pour obtenir le dump avec quelque chose comme ...

jmap -heap:format=b pid
5
jlintz

Comme mentionné ci-dessus, si vous avez un programme non interactif, le collecteur de mémoire (GC) par défaut (compactage) devrait bien fonctionner. Si vous avez un programme interactif et que vous (1) n'allouez pas de mémoire plus rapidement que le GC ne peut suivre, et (2) ne créez pas d'objets temporaires (ou de collections d'objets) trop grands (par rapport au total mémoire JVM maximale) pour permettre au GC de contourner le problème, le CMS est pour vous.

Vous rencontrez des problèmes si vous avez un programme interactif dans lequel le GC n'a pas assez de marge de manœuvre. C'est vrai, peu importe la quantité de mémoire dont vous disposez, mais plus vous en avez, plus la situation empire. En effet, lorsque la mémoire disponible est insuffisante, le CMS manque de mémoire, tandis que les CPG de compactage (y compris G1) mettent tout en pause jusqu'à ce que toute la mémoire ait été vérifiée. Cette pause dans le monde grandit d'autant plus que vous avez de la mémoire. Croyez-moi, vous ne voulez pas que vos servlets fassent une pause de plus d'une minute. J'ai écrit une réponse détaillée de StackOverflow sur ces pauses dans G1.

Depuis lors, ma société est passée à Azul Zing. Elle ne peut toujours pas gérer le cas où votre application a vraiment besoin de plus de mémoire que vous n'en avez, mais jusqu'à ce moment-là, elle fonctionne comme un rêve.

Mais, bien sûr, Zing n'est pas gratuit et sa sauce spéciale est brevetée. Si vous avez plus de temps que d’argent, essayez de réécrire votre application pour utiliser un cluster de machines virtuelles.

À l’horizon, Oracle travaille sur un GC haute performance pour des piles de plusieurs gigaoctets. Cependant, à compter d'aujourd'hui, ce n'est pas une option.

2
David Leppik

un article de Sun sur Java 6 peut vous aider: http://Java.Sun.com/developer/technicalArticles/javase/troubleshoot/

1
anjanb

voici un article sur gc de l'un des champions Java - http://kirk.blog-city.com/is_your_concurrent_collector_failing_you.htm

Kirk, l'auteur écrit "Envoyez-moi vos journaux GC

Je suis actuellement intéressé par l'étude des journaux GC générés par Sun JVM. Étant donné que ces journaux ne contiennent aucune information pertinente sur l’entreprise, il devrait être moins difficile de protéger les informations proriataires. Tout ce que je vous demande, c’est avec le journal que vous mentionnez le système d’exploitation, les informations de version complètes pour le JRE et tous les commutateurs de ligne de commande liés au tas/gc que vous avez définis. J'aimerais également savoir si vous utilisez Grails/Groovey, JRuby, Scala ou autre chose que Java ou parallèlement à celui-ci. Le meilleur réglage est -Xloggc :. Veuillez noter que ce journal ne se réinitialise pas lorsqu'il atteint la taille limite de votre système d'exploitation. Si je trouve quelque chose d'intéressant, je serai heureux de vous donner un résumé très rapide en retour. "

1
anjanb

Il y a quelques années, j'ai comparé JRockit et la machine virtuelle Java pour un tas de 12G. JRockit a gagné, et le support Linux d'énormes pages a rendu notre test plus rapide de 20%. Le test YMMV nécessitait beaucoup de ressources processeur/mémoire et était principalement mono-thread.

1
ShabbyDoo

Si vous passez en 64 bits, vous utiliserez plus de mémoire. Les pointeurs deviennent 8 octets au lieu de 4. Si vous créez de nombreux objets, vous pouvez vous en apercevoir puisque chaque objet est une référence (pointeur).

J'ai récemment alloué 15 Go de mémoire en Java à l'aide de la machine virtuelle Java Sun 1.6, sans aucun problème. Bien que tout ne soit attribué qu'une seule fois. Peu plus de mémoire est allouée ou libérée après la quantité initiale. C’était sous Linux, mais j’imagine que la JVM de Sun fonctionnera tout aussi bien sous Windows 64 bits.

1
Chris de Vries

Vous devriez essayer de lancer visualgc avec votre application. C’est un outil de visualisation de tas qui fait partie du téléchargement de jvmstat à l’adresse http://Java.Sun.com/performance/jvmstat/

C'est beaucoup plus facile que de lire les journaux du GC.

Cela vous aide rapidement à comprendre le fonctionnement des parties (générations) du tas. Bien que votre tas total puisse atteindre 10 Go, les différentes parties du tas seront beaucoup plus petites. Les GC dans la partie Eden du tas sont relativement peu coûteux, alors que les GC complets dans l'ancienne génération sont chers. Dimensionner votre tas de sorte que l'Eden soit grand et que l'ancienne génération ne soit presque jamais touchée est une bonne stratégie. Cela peut entraîner un très gros tas, mais bon, si la machine virtuelle ne touche jamais à la page, c'est juste une page virtuelle et ne nécessite pas de mémoire vive.

1
tpgould

Sun utilise depuis un certain temps un JVM 64 bits Itanium, bien que l’itanium ne soit pas une destination populaire. Les machines virtuelles Java 64 bits de Solaris et Linux devraient être ce que vous devriez être après.
Quelques questions

1) votre application est-elle stable?
2) avez-vous déjà testé l'application dans une JVM 32 bits?
3) puis-je utiliser plusieurs machines virtuelles sur la même boîte? 

Je pense que le système d’exploitation 64 bits de Windows sera stable au bout d’un an environ, mais jusqu’alors, solaris/linux pourrait être un meilleur choix.

0
anjanb

La mémoire maximale que XP peut adresser est de 4 Go ( ici ). Donc, vous ne voudrez peut-être pas utiliser XP pour cela (utilisez un système d'exploitation 64 bits).

0
Milhous