77 votes

Java : des tas de données très volumineux

Quelqu'un a-t-il une expérience de l'utilisation de très grands tas, 12 Go ou plus, en Java ?

  • Le GC rend-il le programme inutilisable ?
  • Quels paramètres GC utilisez-vous ?
  • Quelle JVM, Sun ou BEA, serait la mieux adaptée à cette situation ?
  • Quelle plate-forme, Linux ou Windows, est la plus performante dans de telles conditions ?
  • Dans le cas de Windows, y a-t-il une différence de performance entre Vista et XP en 64 bits sous des charges de mémoire aussi élevées ?

76voto

Si votre application n'est pas interactive et que les pauses GC ne sont pas un problème pour vous, il ne devrait pas y avoir de problème pour que Java 64 bits puisse gérer des tas très importants, même de plusieurs centaines de Go. Nous n'avons pas non plus remarqué de problèmes de stabilité sous Windows ou Linux.

Cependant, lorsque vous devez maintenir les pauses GC à un niveau bas, les choses deviennent vraiment désagréables :

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

  2. Le meilleur choix est probablement le collecteur CMS, activé par -XX:+UseConcMarkSweepGC. Le collecteur CMS arrête l'application uniquement pour la phase initiale de marquage et les phases de remarque. Pour les très petits tas comme < 4 Go, ce n'est généralement pas un 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 l'arrêt complet du monde, mais peut encore être un problème pour les très grands tas.

  3. Lorsque le ramasseur de déchets CMS n'est pas assez rapide pour terminer son opération avant que la génération permanente ne se remplisse, il revient à la GC standard "stop-the-world". Attendez-vous à des pauses d'environ 30 secondes ou plus pour des tas d'une taille de 16 Go. Vous pouvez essayer d'éviter cela en maintenant 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 ce problème est important, car le CMS n'utilise qu'un seul cœur. Évidemment, attention, il y a pas de garantissent que le CMS ne retombe pas sur le collecteur STW. Et lorsqu'il le fait, cela se produit généralement lors des pics de charge, et votre application est morte pendant plusieurs secondes. Vous ne voudriez 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 du CMS, mais nous l'avons essayé et observé :

    • Son débit est inférieur à celui du CMS.
    • En théorie, il devrait éviter de collecter d'abord les blocs de mémoire les plus populaires, mais il atteint rapidement un état où presque tous les blocs sont "populaires", et les hypothèses sur lesquelles il est basé cessent tout simplement de fonctionner.
    • Enfin, la solution de repli "stop-the-world" existe toujours pour G1 ; demandez à Oracle quand ce code est censé être exécuté. S'ils répondent "jamais", demandez-leur pourquoi ce code est là. Donc, à mon avis, G1 ne fait pas disparaître l'énorme problème de tas de Java, il ne fait que le rendre (sans doute) un peu plus petit.
  5. Si vous avez de l'argent pour un gros serveur avec une grosse mémoire, vous avez probablement aussi de l'argent pour une bonne technologie GC sans pause, accélérée par du matériel commercial, comme celle proposée par Azul. Nous avons un de leurs serveurs avec 384 Go de RAM et cela fonctionne vraiment bien - pas de pauses, 0 ligne de code "stop-the-world" dans la GC.

  6. Écrivez en C++ la partie de votre application qui nécessite beaucoup de mémoire, comme l'a fait LinkedIn avec le traitement des graphes sociaux. Vous n'éviterez pas tous les problèmes en procédant ainsi (par exemple, la fragmentation du tas), mais il serait certainement plus facile de maintenir les pauses à un niveau bas.

17voto

Scott Sellers Points 211

Je suis PDG d'Azul Systems, donc mon opinion sur ce sujet est évidemment biaisée ! :) Ceci étant dit...

Gil Tene, directeur technique d'Azul, donne un bon aperçu des problèmes liés au Garbage Collection et passe en revue les différentes solutions dans son article intitulé "Garbage Collection". Comprendre la collecte d'ordures de Java et ce que vous pouvez faire à ce sujet et vous trouverez des détails supplémentaires dans cet article : http://www.infoq.com/articles/azul_gc_in_detail .

Le collecteur d'ordures C4 d'Azul dans notre JVM Zing est à la fois parallèle et simultané, et utilise le même mécanisme GC pour la nouvelle et l'ancienne génération, travaillant simultanément et compactant dans les deux cas. Plus important encore, C4 n'a pas de solution de repli "stop-the-world". Tout le compactage est effectué en même temps que l'application en cours d'exécution. Nous avons des clients qui exécutent de très gros fichiers (des centaines de Go) avec des temps de pause GC inférieurs à 10 msec, et selon l'application, souvent inférieurs à 1-2 msec.

Le problème avec CMS et G1 est qu'à un moment donné, la mémoire du tas de Java doit être compactée, et ces deux ramasseurs de déchets arrêtent le monde/STW (c'est-à-dire mettent l'application en pause) pour effectuer le compactage. Ainsi, si CMS et G1 peuvent repousser 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 si faibles, même pour des tas de taille gigantesque.

14voto

Ichorus Points 2497

Nous avons une application à laquelle nous allouons 12-16 Go, mais elle n'atteint réellement que 8-10 Go en fonctionnement normal. Nous utilisons la JVM de Sun (nous avons essayé celle d'IBM et c'était un peu un désastre, mais c'était peut-être de l'ignorance de notre part... J'ai des amis qui ne jurent que par elle et qui travaillent chez IBM). Tant que vous donnez à votre application de l'espace pour respirer, la JVM peut gérer des tailles de tas importantes sans trop de GC. La clé est de disposer de beaucoup de mémoire "supplémentaire".
Linux est presque toujours plus stable que Windows et quand il n'est pas stable, il est beaucoup plus facile de comprendre pourquoi. Solaris est également solide comme le roc et vous avez aussi DTrace :) Avec ce genre de charges, pourquoi diable utiliseriez-vous Vista ou XP ? Vous ne cherchez que des ennuis. Nous ne faisons rien d'extraordinaire avec les paramètres GC. Nous réglons l'allocation minimale pour qu'elle soit égale à l'allocation maximale afin qu'elle n'essaie pas constamment de redimensionner, mais c'est tout.

9voto

Joel Hoff Points 1537

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

Je n'ai jamais rencontré de problèmes de garbage collection avec l'application basée sur Linux, sauf lorsque je me rapprochais de la taille limite du tas. Pour éviter les problèmes de "thrashing" inhérents à ce scénario (trop de temps passé à faire du garbage collection), j'ai simplement optimisé l'utilisation de la mémoire dans le programme de façon à ce que les pics d'utilisation soient environ 5-10% en dessous de la taille limite du tas de 64 Go.

Cependant, avec une autre application fonctionnant sous Solaris, j'ai rencontré d'importants problèmes de collecte de déchets, ce qui m'a obligé à procéder à de nombreux ajustements. Cela consistait principalement en trois étapes :

  1. Permet/impose l'utilisation du ramasseur de déchets 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. Voir " Optimisation de la collecte d'ordures de la machine virtuelle HotSpot de Java SE 6 "pour plus de détails.

  2. La mise en place extensive et apparemment ridicule de variables locales à "null" après qu'elles ne soient plus nécessaires. La plupart d'entre elles étaient des variables qui auraient dû faire l'objet d'un ramassage après être sorties de leur périmètre, et il ne s'agissait pas de fuites de mémoire puisque les références n'étaient pas copiées. Cependant, cette stratégie de "main tendue" pour faciliter la collecte des déchets était inexplicablement nécessaire pour une raison quelconque pour cette application sous la plate-forme Solaris en question.

  3. Utilisation sélective de l'appel de la méthode System.gc() dans des sections de code clés après de longues périodes d'allocation temporaire d'objets. Je suis conscient des mises en garde standard contre l'utilisation de ces appels, et de l'argument selon lequel ils devraient normalement être inutiles, mais j'ai trouvé qu'ils étaient essentiels pour maîtriser le ramassage des ordures lors de l'exécution de cette application gourmande en mémoire.

Les trois étapes ci-dessus ont permis de contenir l'application et de la faire fonctionner de manière productive à environ 60 Go d'utilisation du tas, au lieu de la faire croître de manière incontrôlée jusqu'à la limite de 128 Go qui était en place. Le collecteur d'ordures parallèle, en particulier, a été très utile car les cycles de collecte d'ordures majeurs sont coûteux lorsqu'il y a beaucoup d'objets, c'est-à-dire que le temps requis pour une collecte d'ordures majeure est fonction du nombre d'objets dans le tas.

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

8voto

kohlerm Points 1672

12Gb ne devrait pas être un problème avec une implémentation décente de la JVM telle que Hotspot de Sun. Je vous conseille d'utiliser le collecteur Concurrent Mark and Sweep ( -XX:+UseConcMarkSweepGC) lorsque vous utilisez une VM SUN, sinon vous risquez de faire face à de longues phases de "stop the world", où tous les threads sont arrêtés pendant un GC.

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X