Le profilage d'applications Java
Introduction
Le profilage des applications Java permet de résoudre des problématiques de performances, qui peuvent provoquer des dysfonctionnements d’applications.
Il peut s’agir d’une consommation mémoire excessive car des objets sont mal relâchés par le système de gestion automatique de la mémoire intégrée dans la JVM, une quantité de mémoire initiale mal dimensionnée, des threads qui sont en interblocages, etc.
Le profilage peut sembler une activité marginale qui intervient assez rarement dans la vie d’un développeur Java, et c’est assez vrai, mais l’exploitation des données de profilage augmente significativement la maîtrise de l’environnement Java, par la compréhension profonde des mécanismes qui régissent le fonctionnement des applications produites en Java.
Le profilage est enfin un outil indispensable pour expliquer des comportements inexplicables, lorsque la lecture du code ne suffit pas. C’est une compétence qui peut sauver de situations inextricables.
Ce chapitre adopte une démarche expérimentale pour découvrir à la fois les outils qui, dans NetBeans, intègrent le profilage et le rendent facile à exploiter, et les grands principes de fonctionnement de la plateforme Java, qui seront mis au jour par ces outils.
Avant de commencer : les grands principes de fonctionnement de la JVM
Une bonne connaissance du fonctionnement de la Machine virtuelle Java (Java Virtual Machine ou JVM) est un point incontournable pour une bonne compréhension des comportements des programmes Java.
C’est ce qui permet à Java d’avoir cette relative simplicité d’implémentation, qui autorise les développeurs à se concentrer sur le code métier et moins sur certains aspects techniques, tels que la gestion de la mémoire ou la compatibilité avec le système d’exploitation cible.
Il y a au moins deux facettes de la JVM qu’il convient d’aborder dans l’optique de la compréhension d’un problème de performance : la facette "gestion automatisée de la mémoire", notamment les différentes zones mémoire associées à l’algorithme de garbage collection (recyclage de la mémoire non utilisée), et la facette ’’gestions des fils d’exécution’’ (threads) qui rend Java nativement multi-thread.
1. Gestion automatique de la mémoire
La gestion automatique de la mémoire dans la JVM est une des raisons majeures qui a fait de Java le langage le plus favorisé pour le développement des projets d’applications métier.
Cette gestion automatisée, assez performante (bien que pas infaillible), a permis d’augmenter significativement la productivité des développeurs en les laissant se concentrer sur des problèmes d’implémentation...
Premier profilage d’une application avec NetBeans
Dans ce premier profilage, l’application graphique Swing, vue au chapitre Le développement d’applications riches, sera analysée. Le profilage ne s’arrête pas aux applications lourdes de bureau, il peut s’appliquer à des serveurs web hébergeant plusieurs applications web différentes. C’est d’ailleurs dans ce domaine que le profilage est le plus souvent utilisé, notamment pour suivre le comportement d’une application soumise à un stress provoqué par son utilisation massive par des utilisateurs simultanés. Le profilage permet ici de valider que l’application tient la charge et qu’il est possible de la déployer et de la mettre à disposition en toute confiance. Pour résumer, le profilage peut s’appliquer sur n’importe quel programme qui s’exécute sur une JVM.
1. Déclenchement et configuration du premier profilage
Il est possible de profiler une application depuis NetBeans directement depuis le menu disponible par un clic droit sur un projet, comme montré dans la copie d’écran ci-après.
Déclenchement du profilage pour un projet
Après avoir cliqué, la fenêtre de profilage apparaît.
Accueil de l’outil de profilage dans NetBeans
La fenêtre indique qu’aucune donnée permettant de faire un profilage n’a été trouvée. Afin d’activer la récolte de ces données, il faut s’attacher à une application Java s’exécutant sur la même machine.
a. Lancement et calibration
Pour profiler l’application Swing développée au chapitre Le développement d’applications riches, il faut la lancer. Une fois démarrée, elle devrait apparaître dans la liste des applications sur lesquelles il est possible d’attacher l’outil de profilage. Cette liste s’affiche lorsque l’on clique sur le bouton avec un symbole de chronomètre.
Lancement d’un profilage
Après avec cliqué sur cette entrée de menu, NetBeans nous informe que la calibration de la JVM pour l’environnement choisi n’est pas faite.
Calibration à effectuer avant le premier profilage
En cliquant sur Show...
Analyses possibles relatives à la mémoire
Plusieurs méthodes d’analyse sont possibles pour vérifier l’utilisation de la mémoire : les analyses globales (en cours d’exécution) et les analyses à froid.
1. Analyse globale de la mémoire
Les analyses à chaud permettent de se rendre compte du comportement en matière de gestion de la mémoire du programme observé. L’observation de la mémoire est répartie sur deux outils de la console de profilage : l’onglet Telemetry, qui contient les statistiques de garbage collection et de l’occupation mémoire du Heap, et l’onglet Objects, qui recense les instances en cours d’utilisation du programme.
a. Observation et interprétation du comportement de la mémoire
Pour mettre en avant le comportement du programme du point de vue de la mémoire, il est possible de grossir le trait en chargeant artificiellement ce programme. Dans le programme qui est observé dans ce chapitre, il est possible de simuler cette charge par un appui répété (une trentaine de fois) sur le bouton de chargement du CSV : Charger le csv
Utilisation de l’application Swing pour l’exemple de profilage
On observe alors le comportement suivant dans l’onglet Telemetry :
Observation de la consommation mémoire
La mémoire utilisée augmente assez fortement au moment du test (12:01) puis est subitement libérée.
Notez que la progression lente de l’utilisation mémoire jusqu’à peu avant le début du test de charge est due à l’action de l’outil de profilage pour la surveillance et l’instrumentation des classes. La courbe théorique sans profilage devrait être plate jusqu’au déclenchement du test de charge.
Cette diminution brutale correspond à un évènement de garbage collection, comme l’indique ce second graphique :
Métriques liées au garbage collector
La courbe en bleue (tracé en bâton) symbolise les moments où le garbage collector se met en marche (GC Intervals). La courbe en jaune (en créneau) indique le nombre de générations survivantes. Elle permet l’observation de l’évolution des générations...
Analyses possibles relatives à l’utilisation du processeur
L’analyse des temps d’exécution permet de se rendre compte d’éventuels problèmes de lenteur qui peuvent être constatés à l’utilisation d’une application.
Pour activer ce mode de l’outil de profilage, il faut sélectionner le mode Methods.
Activation des métriques de méthodes
Dans ce cas, l’onglet Objects disparaît au profit de l’onglet Methods. Dans cet onglet, il est alors possible de suivre les temps d’exécution par classe et par méthode.
Après un clic sur le bouton Charger le csv (et nettoyage préalable des statistiques), le résultat est le suivant :
Suivi du temps d’exécution par méthode
Il est possible de constater que le temps d’exécution de l’action de chargement est enregistré à 55 ms. Ce temps se décompose en 43,6 ms pour l’exécution de la méthode loacCSVActionPerformed() elle-même (analyse du contenu CSV, mise à jour de l’interface), et 6 ms supplémentaires sont passées dans la méthode countLinesHavingMissingValues()(n’apparaît pas sur l’écran) ; le reste tient à l’application des styles graphiques gérée par les classes dont le package débute...
Autres possibilités du profileur de NetBeans
NetBeans offre d’autres possibilités qui ne sont pas démontrées dans ce chapitre, telles que les points de profilage (l’équivalent des points d’arrêt dans le cadre du débogage d’une application) et la prise de snapshots, qui sont des dumps légers et qui peuvent fournir un intermédiaire suffisant pour constater la progression de l’occupation mémoire.
Deux autres onglets, comme l’observation des Locks permettant de visualiser les points de synchronisation et les statistiques d’attente de chaque thread sur ces points, et les performances de requêtes SQL sont également disponibles et suivent les mêmes logiques de fonctionnement.
Une alternative plus contraignante à utiliser est l’outil VisualVM, qui n’est pas autant intégré que l’outil de profilage de NetBeans, mais qui possède des fonctionnalités assez intéressantes et plus facilement à jour puisqu’il est mis à jour à chaque version majeure de Java. Cet outil permet notamment plus de précision dans le suivi des zones mémoire de Java, en particulier l’occupation du MetaSpace.