Pour les applications conteneur, il est difficile de détecter les problèmes dus à une surconsommation de mémoire. Si la consommation dépasse la limite de mémoire du conteneur, une application peut échouer silencieusement sans laisser de traces.
Dans cet article, je vais passer en revue certaines des techniques qui peuvent être utilisées pour identifier la source de la consommation de mémoire dans une application conteneur Java.
Type de Mémoire
Dans un application Java typique, la mémoire peut être divisée en grande partie en mémoire d’objet et hors mémoire d’objet. La mémoire d’objet peut être définie en fournissant les paramètres JVM pertinents lors du démarrage de toute application Java.
La mémoire hors mémoire d’objet se compose de la mémoire native utilisée par le JVM lui-même ou par toute bibliothèque utilisée dans l’application via l’interface native Java (JNI).
Méthode
Pour la mémoire d’objet, un dump de tas peut être pris et analysé à l’aide d’outils d’analyse de dump de tas. L’un des meilleurs outils pour l’analyse de dump de tas est eclipse MAT.
Java propose un mécanisme pour suivre l’allocation de mémoire native en activant le suivi de mémoire native, mais cela peut ne pas révéler toute la mémoire allouée par les bibliothèques natives.
Jemalloc est un utilitaire qui peut être utilisé pour suivre la mémoire allouée par les bibliothèques natives. La mémoire native est allouée à l’aide d’un allocateur de mémoire par défaut appelé malloc. Jemalloc est une implémentation générique de malloc avec laquelle le suivi de l’allocation de mémoire peut être activé. Il suit toutes les allocations de mémoire native et génère des dumps de profil de tas.
Ces profils de tas peuvent ensuite être analysés à l’aide de l’utilitaire Jeprof. Jeprof génère le rapport d’allocation de tas, mettant en évidence la mémoire utilisée par les fonctions dans l’application.
Analyse
Voici une analyse de mémoire d’une application Java de conteneur d’exemple. L’application charge un modèle Tensorflow d’exemple pour permettre l’utilisation de la mémoire native et s’exécute dans un conteneur Docker.
Voici la consommation de mémoire Docker. Elle indique 254 Mo. Essayons de localiser la source de la consommation de mémoire.
Mémoire Totale
Pour avoir une idée de la mémoire totale utilisée par le processus de l’application, nous pouvons vérifier la Taille du Jeu Résident (RSS). Il s’agit de la mémoire commitée totale qui réside dans la mémoire principale ou RAM. Il existe plusieurs utilitaires qui peuvent aider à vérifier cela comme top, ps ou pmap.
Vérifier l’utilisation RSS n’aide pas à identifier la source principale de consommation. Pour l’application d’exemple, en utilisant la commande ci-dessous, la RSS totale est de 376 Mo.
ps --no-header -o rss $(pidof java)
Analyse du tas
Voici la consommation de mémoire du tas telle qu’elle est générée par l’outil Eclipse MAT. La mémoire retenue totale est indiquée comme étant de 2,2 Mo, ce qui est bien en dessous de la consommation totale de mémoire indiquée par Docker et indique que la majorité de la consommation provient de la zone non-tas.
Analyse de la mémoire native
En examinant le résumé de la mémoire native à l’aide de la commande ci-dessous, la consommation totale de mémoire semble être d’environ 99 Mo. Cependant, cette valeur est inférieure à la consommation totale de mémoire et n’identifie pas avec précision la cause racine du problème.
jcmd $(pidof java) VM.native_memory \
| grep -P "Total.*committed=" \
| grep -o -P "(?<=committed=)[0-9]+(?=KB)"
Analyse de la mémoire hors tas
Une analyse utilisant Jemalloc et Jeprof révèle que l’utilisation de la mémoire native est principalement attribuable à la bibliothèque Tensorflow, avec une consommation totale d’environ 112 Mo.
Cette information fournit une indication claire de la source de l’utilisation de la mémoire native et peut être étudiée plus en détail pour réduire toute consommation excessive.
Conclusion
L’analyse de la mémoire Java est cruciale, en particulier pour les applications basées sur des conteneurs. Connaître la source de la consommation de mémoire dans une application peut nous aider à comprendre les besoins en mémoire et à réduire les coûts de l’application en supprimant toute consommation inutile.
Lors de la vérification de la consommation de mémoire, il est nécessaire de localiser tous les types de mémoire et leurs sources. L’analyse des dumps de tas peut localiser les sources de consommation de mémoire du tas, et Jemalloc et Jeprof sont utiles pour localiser les sources de consommation de mémoire native.
Lien du Code d’Application d’Exemple
Source:
https://dzone.com/articles/java-container-application-memory-analysis