Tunning JVM

L’objectif de cette opération est d’améliorer le fonctionnement de la JVM en minimisant le temps de pause introduit par l’exécution du ramasse miette.

Avant de se lancer dans l’optimisation du GC, qui est une activité chronophage et pour laquelle le gain en performance risque d’être minime, mieux vaut s’être assuré que l’allocation mémoire de l’application est optimale. Pour cela nous n’allons pas réaliser immédiatement un profiling mémoire de l’application mais seulement vérifier l’empreinte mémoire de l’application en fonctionnement nominal, et s’assurer par la même occasion que la surcharge des pauses introduites par le GC n’est pas trop importante. Un overhead de 5 à 10% maximum peut être toléré pour une application de gestion. Bien entendu pour mesurer le seuil de tolérance, il faut prendre en compte le type d’application. En effet, une application de type temps réel n’aura pas les mêmes exigences de disponibilité qu’une application de gestion.

Pour mesurer cet overhead, il existe plusieurs méthodes que nous n’allons pas détailler dans cet article. Nous nous bornerons à tracer le fonctionnement du GC. Pour cela, nous introduisons les paramètres suivants dans la ligne de commande java.  Ces paramètres sont, pour la plupart, spécifiques à la JVM de Sun, mais chaque JVM propose des paramètres similaires.

-verbose:gc -XX:+PrintGCTimeStamps  -Xloggc:<nom du fichier de log>

-verbose:gc Mise en place du mode trace du GC

-XX:+PrintGCTimeStamps  Indique l’heure à laquelle le GC s’est déclenché. Exprimée en seconde depuis le lancement de la JVM.

-Xloggc déclaration du fichier de log dans lequel les traces du GC seront journalisées

Les traces produites par ces options sont de ce type pour la JVM hotspot :

35680.853: [Full GC 693213K->454828K(1533568K), 2.4587420 secs]

39284.006: [Full GC 677573K->456159Kv(1533568K), 2.3361990 secs]

42887.035: [Full GC 692601K->459046K(1533568K), 2.3706670 secs]

46490.099: [Full GC 562666K->453585K(1533568K), 2.3002020 secs]

50093.093: [Full GC 613753K->452194K(1533568K), 1.9766310 secs]

La lecture de ces traces n’est pas très compliquée.

35680.853: [Full GC 693213K->454828K(1533568K), 2.4587420 secs]

35680.853 est le timestamp de déclenchement du GC, généré par le paramètre PrintGCTimeStamps  .

Full GC indique le type du GC

693213K indique la quantité de mémoire avant le GC

454828K indique la quantité de mémoire après le GC

1533568K en simplifiant on peut dire qu’il s’agit de la quantité totale de mémoire allouée à la heap (elle ne tient pas compte de la zone permanente)

2.4587420 secs est le temps de pause du GC

On peut avoir des traces différentes selon les options que l’on utilise et les versions de JVM mais pour les besoins de cet article ces traces sont parfaites.

Tout d’abord nous vous recommandons d’être vigilants sur l’interprétation de ces traces. Il nous est arrivé de voir des personnes qui lançaient des alertes à la lecture de ces quelques lignes (voir ci-dessus) en demandant à un éditeur de logiciel d’être plus sérieux dans la gestion de la mémoire. Ors ces traces ne permettent pas de faire ce type de remarques. En effet, on constate uniquement que la JVM lance un GC «dit « majeur » toutes les heures et la collection dure un peu plus de 2 secondes en moyenne. Ce fonctionnement correspond tout à fait au paramétrage de la JVM qui avait été fait (en définissant notamment le délai de déclenchement des GC distribués) chez ce client.

Ces traces nous permettent par contre de déterminer l’empreinte mémoire de l’application. Elle peut être obtenue à partir de la quantité de mémoire résiduelle après les GC de type « majeur » (ici Full GC). Plus l’empreinte mémoire est importante moins il reste de mémoire disponible pour allouer des objets et par conséquent plus la périodicité de déclenchement des GC va augmenter pour libérer la mémoire. L’overhead des collections augmente donc inévitablement, et le temps alloué au fonctionnement de l’application diminue.

L’overhead du GC est le rapport entre le temps de pause et le délai entre 2 déclenchements de GC. Il indique le ratio de surcharge du GC vs le temps total de fonctionnement. Au dessous du seuil de 5% aucune mesure n’est nécessaire, entre 5% et 10% il y peut y avoir quelques ajustements à réaliser mais le gain de performance n’est pas significatif au regard des améliorations qui peuvent être apportées au code de l’application. Au-delà de 10% il peut être intéressant d’améliorer le fonctionnement des GC. Mais une chose est sure, si l’empreinte mémoire est importante, il est beaucoup plus intéressant d’optimiser l’allocation mémoire de l’application plutôt que d’essayer de diminuer le temps de pause des GC.

www.jperf.com

Publicités

A propos jlerbsc

founder of JavaPerf Consulting Http://www.jperf.com
Cet article a été publié dans JVM. Ajoutez ce permalien à vos favoris.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s