Pourquoi analyser son heap
Un heap dump est une image à l’instant T de la mémoire de votre JVM. Il contient généralement les objets et classes dans le heap au moment du dump. Analyser son heap, même si votre application semble fonctionner correctement peut vous permettre d’en améliorer les performances, de pointer une classe ou une méthode qui serait consommatrice de mémoire dans le but de mieux comprendre l’exécution de votre code.
Comment faire un dump
Avant toute chose, il faudra s’assurer que votre espace disque est suffisant pour générer le dump. Il sera en moyenne aussi volumineux que le maximum de mémoire alloué à votre JVM (par défaut 8Mo, customisable via l’option de JVM -Xmx). Second point important, le temps de l’exécution du heap dump, votre application sera fortement ralentie voire complètement inaccessible.
jconsole
Avec la jconsole, incluse dans le JDK :

Le premier paramètre p0 est l’endroit où écrire le résultat du dump, et le second paramètre p1 ‘live’ qui permet d’inclure (false) ou d’exclure (true) les objets prêts à être garbage collectés.
jmap
Avec la jmap, inclus dans le JDK :
jmap -dump:live,format=b, file=<file-path> <pid>
L’option live est la même que dans l’opération jmx, à savoir inclure ou non les objets qui vont être garbage collectés.
Le format ‘b’ signifie binaire. C’est le format par défaut et celui qui nous intéresse pour notre future analyse.
Le file est le chemin où écrire le résultat du dump.
Enfin le pid est l’id du process Java sur lequel le dump sera effectué.
HeapDumpOnOutOfMemoryError
Les précédents outils permettent de faire des heap dumps à la demande. Mais quand votre application génère un OutOfMemoryError, il s’avère utile que le heap dump soit généré automatiquement. Il suffit d’ajouter les options suivantes lors du lancement de votre JVM :
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/tmp/heapdump.bin
Par défaut le dump sera enregistré à l’endroit où votre application est lancée.
L’option -XX:HeapDumpPath vous permettra de spécifier un autre chemin pour enregistrer votre dump (si le file system où votre application est lancé n’a pas assez d’espace libre par exemple).
Tips : Si vous avez oubliez d’ajouter cette option de JVM (ou tout autre option) et que vous ne pouvez pas redémarrer votre JVM, sachez qu’il est possible d’ajouter des options de JVM à chaud via la jconsole :

Eclipse Memory Analyser
A noter qu’il est possible de faire vos dumps directement dans cet outil. Sachez qu’il vous faudra avoir autant de RAM disponible sur la machine qui fait l’analyse, que la taille de votre dump.
Exemple d’analyse
Pour illustrer l’article, j’ai créé une application avec une boucle infinie qui va faire un OutOfMemory et générer un dump automatiquement. J’ai préalablement configuré la taille maximum de mon heap à 8Mo.



A partir de ce dump, je vais commencer mon analyse. Si je charge mon dump dans Eclipse Memory Analyser, j’obtiens cette vue :


Quand nous entrons dans les détails de la stack trace nous obtenons l’emplacement exact de ce qui a entrainé notre OutOfMemory et nous permettra donc d’agir en conséquence :

Le problème ici est donc en cohérence avec l’application que j’ai codé : la mémoire de ma JVM a été saturé par la liste que j’ai peuplé à l’infini.
Notes
Toutes les opérations effectuées ont été faite sur la base du JDK 17 téléchargé sur le site https://adoptium.net/. Le but n’est pas d’expliquer ce qu’est la stack memory et le heap space mais de décrypter son contenu afin de mieux comprendre votre application Java.
Il existe des outils d’analyse en ligne. Ils proposent des petits plus sur l’analyse de vos dumps comme des conseils pour réduire votre consommation de mémoire ou des mises en forme des résultats attractifs. Cependant, gardez bien à l’esprit que votre dump sera envoyé sur un serveur tiers et que son contenu en dit bien plus que vous ne pouvez l’imaginer sur votre application.
src/main/resources
Si vous souhaitez approfondir le sujet, je vous invite à consulter ces liens :
https://www.baeldung.com/java-stack-heap
https://www.jmdoudoux.fr/java/dej/chap-jvm.htm#jvm-1
https://help.eclipse.org/latest/index.jsp?topic=/org.eclipse.mat.ui.help/welcome.html
https://www.geeksforgeeks.org/different-ways-to-capture-java-heap-dumps/
Nicolas Lenouvel
Consultant senior
Proxiad Axe Seine