Différents moyens de capturer les vidages de segments de mémoire Java

Différentes façons de capturer des vidages de segments de mémoire Java

1. introduction

Dans cet article, nous allons montrer différentes manières de capturer un vidage de tas en Java.

A heap dump is a snapshot of all the objects that are in memory in the JVM at a certain moment. Ils sont très utiles pour résoudre les problèmes de fuite de mémoire et optimiser l'utilisation de la mémoire dans les applications Java.

Heap dumps are usually stored in binary format hprof files. Nous pouvons ouvrir et analyser ces fichiers en utilisant des outils comme jhat ou JVisualVM. De plus, pour les utilisateurs d'Eclipse, il est très courant d'utiliserMAT.

Dans les sections suivantes, nous allons passer en revue plusieurs outils et approches pour générer un vidage de tas et nous montrerons les principales différences entre eux.

2. Outils JDK

Le JDK est livré avec plusieurs outils permettant de capturer des vidages de segments de mémoire de différentes manières. All these tools are located under the bin folder inside the JDK home directory. Par conséquent, nous pouvons les démarrer à partir de la ligne de commande tant que ce répertoire est inclus dans le chemin système.

Dans les sections suivantes, nous montrerons comment utiliser ces outils pour capturer des vidages de tas.

2.1. jmap

Jmap est un outil pour imprimer des statistiques sur la mémoire d'une machine virtuelle Java en cours d'exécution. Nous pouvons l'utiliser pour des processus locaux ou distants.

Pour capturer un vidage de tas en utilisant jmap, nous devons utiliser l'optiondump:

jmap -dump:[live],format=b,file= 

Parallèlement à cette option, nous devrions spécifier plusieurs paramètres:

  • live: s'il est défini, il n'imprime que les objets qui ont des références actives et rejette ceux qui sont prêts à être récupérés. Ce paramètre est optionnel

  • format=b: spécifie que le fichier de vidage sera au format binaire. Si non défini le résultat est le même

  • file: le fichier dans lequel le vidage sera écrit

  • pid: id du processus Java

Un exemple serait comme ceci:

jmap -dump:live,format=b,file=/tmp/dump.hprof 12587

N'oubliez pas que nous pouvons facilement obtenir lespid d'un processus Java en utilisant la commandejps.

Keep in mind thatjmap was introduced in the JDK as an experimental tool and it’s unsupported. Par conséquent, dans certains cas, il peut être préférable d'utiliser d'autres outils à la place.

2.2. jcmd

jcmd est un outil très complet qui fonctionne en envoyant des demandes de commande à la machine virtuelle Java. Nous devons l’utiliser sur la même machine que le processus Java.

One of its many commands is the GC.heap_dump. Nous pouvons l'utiliser pour obtenir un vidage de tas simplement en spécifiant lespid du processus et le chemin du fichier de sortie:

jcmd  GC.heap_dump 

Nous pouvons l'exécuter avec les mêmes paramètres que ceux que nous utilisions auparavant:

jcmd 12587 GC.heap_dump /tmp/dump.hprof

Comme avec jmap, le dump généré est au format binaire.

2.3. JVisualVM

JVisualVM is a tool with a graphical user interface that lets us monitor, troubleshoot and profile Java applications. L'interface graphique est simple mais très intuitive et facile à utiliser.

L'une de ses nombreuses options nous permet de capturer un vidage de tas. Si nous cliquons avec le bouton droit sur un processus Java et sélectionnons l'option“Heap Dump”, l'outil créera un vidage de tas et l'ouvrira dans un nouvel onglet:

image

Notez que nous pouvons trouver le chemin du fichier créé dans la section“Basic Info”.

3. Capturer automatiquement un vidage de tas

Tous les outils que nous avons présentés dans les sections précédentes sont destinés à capturer manuellement les vidages de tas à un moment précis. Dans certains cas, nous voulons obtenir un vidage du tas lorsqu'unjava.lang.OutOfMemoryError se produit afin que cela nous aide à enquêter sur l'erreur.

Pour ces cas,Java provides the HeapDumpOnOutOfMemoryError command-line option that generates a heap dump when a java.lang.OutOfMemoryError is thrown:

java -XX:+HeapDumpOnOutOfMemoryError

Par défaut, il stocke le vidage dans un fichierjava_pid<pid>.hprof dans le répertoire où nous exécutons l'application. Si nous voulons spécifier un autre fichier ou répertoire, nous pouvons le définir dans l'optionHeapDumpPath:

java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=

Lorsque notre application manque de mémoire en utilisant cette option, nous pourrons voir dans les journaux le fichier créé qui contient le vidage du tas:

java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Dumping heap to java_pid12587.hprof ...
Exception in thread "main" Heap dump file created [4744371 bytes in 0.029 secs]
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
    at com.example.heapdump.App.main(App.java:7)

Dans l'exemple ci-dessus, il a été écrit dans le fichierjava_pid12587.hprof.

Comme on peut le voir, cette option est très utile etthere is no overhead when running an application with this option. Therefore, it’s highly recommended to use this option always, especially in production.

Enfin,this option can also be specified at runtime by using the HotSpotDiagnostic MBean. Pour ce faire, nous pouvons utiliser JConsole et définir l'option VMHeapDumpOnOutOfMemoryError surtrue:

image

Nous pouvons trouver plus d'informations sur les MBeans et JMX dans cearticle.

4. JMX

La dernière approche que nous aborderons dans cet article utilise JMX. We’ll use the HotSpotDiagnostic MBean que nous avons brièvement présenté dans la section précédente. This MBean provides a dumpHeap method qui accepte 2 paramètres:

  • outputFile: le chemin du fichier pour le vidage. Le fichier devrait avoir l'extension hprof

  • live: s'il est défini sur true, il ne vide que les objets actifs en mémoire, comme nous l'avons vu avec jmap auparavant

Dans les sections suivantes, nous allons montrer 2 façons différentes d'appeler cette méthode afin de capturer un vidage de tas.

4.1. JConsole

Le moyen le plus simple d'utiliser le MBeanHotSpotDiagnostic consiste à utiliser un client JMX tel que JConsole.

Si nous ouvronsJConsole et nous nous connectons à un processus Java en cours d’exécution,we can navigate to the MBeans tab and find the HotSpotDiagnostic under*com.sun.management*. In operations, nous pouvons trouver la méthodedumpHeap que nous avons décrite précédemment:

image

Comme indiqué, il suffit d'introduire les paramètresoutputFile etlive dans les champs de textep0 etp1 afin d'effectuer l'opérationdumpHeap.

4.2. Manière programmatique

L'autre façon d'utiliser le MBeanHotSpotDiagnostic est de l'invoquer par programme à partir du code Java.

Pour ce faire, nous devons d'abord obtenir une instanceMBeanServer afin d'obtenir un MBean qui est enregistré dans l'application. Après cela,we simply need to get an instance of a HotSpotDiagnosticMXBean and call its dumpHeap method.

Voyons cela dans le code:

public static void dumpHeap(String filePath, boolean live) throws IOException {
    MBeanServer server = ManagementFactory.getPlatformMBeanServer();
    HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(
      server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
    mxBean.dumpHeap(filePath, live);
}

Notice that an hprof file cannot be overwritten. Par conséquent, nous devons en tenir compte lors de la création d'une application qui imprime des vidages de tas. Si nous ne le faisons pas, nous obtiendrons une exception:

Exception in thread "main" java.io.IOException: File exists
    at sun.management.HotSpotDiagnostic.dumpHeap0(Native Method)
    at sun.management.HotSpotDiagnostic.dumpHeap(HotSpotDiagnostic.java:60)

5. Conclusion

Dans ce didacticiel, nous avons montré plusieurs façons de capturer un vidage de tas en Java.

En règle générale, nous devons nous rappeler de toujours utiliser l'optionHeapDumpOnOutOfMemoryError lors de l'exécution d'applications Java. À d'autres fins, n'importe lequel des autres outils peut être parfaitement utilisé à condition de garder à l'esprit le statut non pris en charge de jmap.

Comme toujours, le code source complet des exemples est disponibleover on GitHub.