SAP Memory Analyzer : voilà un vrai outil pour analyser des Heap Dump Java !

Vous avez développé une application JEE, et depuis son passage en production au moins une fois par jour il y a une erreur Java « OutOfMemoryError ». La première réaction a été de dire : mauvaise configuration de la taille maximale de la JVM… vous avez préconisé 1Go de Max Heap Size, cela n’a pas fonctionné, l’erreur OOME arrive encore… Alors on est passé à 2Go… Toujours l’erreur d’OOME… Aie, et que faire…

Quand vous êtes à ce point, vous pouvez être certain que vous avez une fuite de mémoire (memory leaks) quelque part. Oh, ce n’est pas que vous êtes un mauvais développeur 😉 et que vous ne savez pas bien gerer la mémoire, en effet, parfois un problème de fuite de mémoire peut survenir à cause d’une fonctionnalité activée du serveur d’applications de production et qui rentre en « conflit » avec une brique de l’application. (Je citerai un exemple vécu : le cache (activé) JDBC de la source de données WebSphere 5.1 et un framework maison de mapping O/R)

Quand on a un problème d’OutOfMemory, on commence souvent par activer le mode verbeux du Garbage Collector (GC), c’est une très bonne idée, cela permet d’avoir une petite idée sur le déroulement du problème de mémoire (on peut utiliser l’outil Extensible Verbose Toolkit d’IBM pour ce travail, cf références). Cependant c’est insuffisant pour trouver la cause du problème. Quelques recherches sur Internet vous apprennent qu’il est possible d’avoir une image de la mémoire Java avec la génération d’un « heap dump », ensuite il suffit de l’analyser pour trouver la cause de la fuite de mémoire. Facile à écrire, mais dur à faire…

Commençons par la génération du heap dump. La bonne nouvelle, c’est que depuis les versions Java 1.4.2 update 12, Java 5 update 07 et Java 6, la génération de heap dump est « devenu » facile. Pour avoir un heap dump automatique dès que vous avez une erreur OOME, il faut simplement ajouter ce paramètre -XX:+HeapDumpOnOutOfMemoryError dans les arguments de la JVM. La mauvaise nouvelle, c’est que pour les versions antérieures, c’est plus difficile d’obtenir un heap dump. Cela dépend de l’éditeur de la JVM que vous utilisez (IBM, BEA, Sun, HP, etc), il faut se reporter sur le site de l’éditeur pour trouvez la bonne recette…

Une fois que l’on a trouvé le bon paramètre pour générer son heap dump, il ne reste plus qu’à le mettre en production et attendre l’erreur fatal d’OOME. Quand celle-ci arrive, on attend la génération du fichier qui peut prendre plusieurs minutes car le fichier aura la taille de la JVM au moment de l’erreur. Donc si la taille maximum est à 1Go, le fichier va faire 1Go.

Maintenant que l’on a son fichier heap dump, il faut l’analyser…et là aussi c’est pas simple. Il existe différents moyens, allant du mode texte (via Hprof) vers des outils tels que Heap Analyzer de IBM ou bien HAT (ou JHAT maintenant) de Sun. Le gros problème de ses outils, c’est que c’est quasiment impossible d’ouvrir un heap dump d’1Go avec. Vous avez un OutOfMemoryError de l’outil 😉

La bonne nouvelle c’est que l’éditeur SAP a pensé à nous, à travers son outil d’analyse Memory Analyzer. Ce dernier est basé sur l’environnement RCP d’Eclipse. Il ouvre sans difficulté un heap dump de 1Go, car il analyse le fichier heap dump petit à petit et en créant ses propres fichiers d’index. (Il faut compter environ 1h30 pour ouvrir un fichier 1,2Go sur un portable Vista avec 2Go de RAM, Core 2 Duo 2GHz)

Memory Analyzer dispose de nombreuses fonctionnalités, dont l’une qui va nous intéresser particulièrement : la détection de fuite de mémoire (find memory leaks). De plus il dispose de tutoriaux pour aider à l’analyse de fichier heap dump.

Voici quelques captures d’écran qui en diront plus que mes longs discours :

Détails d’un heap dump.

Détails d'un heap dump

Histogramme, détails par classe : nombre d’objets, taille la plus petite de l’objet, taille des objets

Histogram - Voir les classes, le nombre d'objets,  la plus petite taille de l'objet et la taille totale des objets

Inspector pour avoir le détail et le contenu d’un objet

Inspector

La détection de fuite de mémoire, ici un objet détient à lui tout seul 657 Mo sur 1024 Mo ! Cela sent le memory leaks…

Détection de fuite de mémoire (memory leaks)

Analyse de la fuite mémoire, la cause ici semble être une liste HashMap de + de 490000 objets.

Analyse d'une fuite de mémoire


[Quelques pointeurs]