Presentation on CDI – JSR299

17 février 2012 Laisser un commentaire

View it in Fullscreen !! (More > Fullscreen)

Catégories :CDI, Java / JEE, Uncategorized

Glassfish V3 / JEE6 / Ear modulaire

4 février 2011 Laisser un commentaire

Lors de mon dernier projet JEE6 avec glassfish V3, j’ai été confronté à un problème de compréhension sur la structure d’un ear.
J’avais une structure modulaire avec plusieurs jars ejb gérés avec JPA.
Pour être conforme avec la norme, et pour faire simple, j’ai donc adopté la structure suivante :
– ear\
—- stateless_ejb1.jar
—- stateless_ejb2.jar
—- META-INF\
—————– application.xml
—- lib\
———- log4j.jar

Et maintenant où placer le fichier persistence.xml ?

Il faut que le persistence-unit soit commun à tous mes ejbs. J’ai tout de suite pensé au répertoire META-INF de l’ear mais j’ai appris qu’il est ignoré dans la recherche du persistence.xml.
J’ai tenté de mettre le fichier dans un nouveau projet ejb, mais il n’était pas visible des autres projets ejbs.
La solution a été de packager le fichier persistence.xml dans un jar persistence.jar (ce jar contient seulement un répertoire META-INF et à l’intérieur le fichier persistence.xml) et de mettre ce fichier dans le répertoire lib de l’ear.

Ce qui donne :
– ear\
—- stateless_ejb1.jar
—- stateless_ejb2.jar
—- META-INF\
—————– application.xml
—- lib\
———- persistence.jar
———- log4j.jar

Vive la modularité….

Catégories :Java / JEE Étiquettes : , , , , , ,

OutOfMemory : PermGenSpace sur des framework applicatifs (tels Glassfish ou Tomcat)

21 octobre 2009 1 commentaire

Cet exception signifie qu’une application déployé sur votre framework ne libère pas les objets « classe » lorsqu’elle est déchargée.

La zone de mémoire dite ‘permanent generation space‘ est une zone où réside les objets « classe », et également toutes les chaines de caractères sur lesquels la méthode ‘intern()‘ été appelé.

Une classe est chargée par un classloader, une classe référence son classloader et le classloader référence toutes les classes qu’il a chargé.

Les frameworks applicatifs créé une nouvelle instance de classloader pour chaque application déployée, cela permet d’isoler les applications les unes des autres, et notamment, permet aux différentes applications d’utiliser plusieurs versions de la même classe.

Pour éviter toute fuite mémoire lors d’un déchargement, il faut faire attention à ce que toutes les instances des objets de l’application ne soient plus joignable, sinon le Garbage Collector ne libérera jamais le classloader et toutes les classes qu’il a chargé.

 

Dans quel cas cela se passe mal ?

 

Il faut faire attention à l’utilisation des attributs déclarés ‘static‘ dans les classes que nous définissons.
En effet, un attribut ‘static‘ se trouve référencé dans l’objet classe créé par le classloader.

Disons donc que nous définissons un attribut ‘static‘ et que nous créons un objet dedans.
Jusque la, rien de grave, car cet objet n’est référencé que par cette classe, donc le GC pourra libérer l’objet et la classe.
Mais voila, si cet objet est référencé dans une autre classe, également par un attribut ‘static’, alors le GC considère l’objet comme ‘unreachable‘, et ne le libère pas, et donc ne libère pas non plus la classe, ni le classloader, ni toutes les classes du classloader.

 

Comment diagnostiquer le problème ?

 
Il faut obtenir un dump de la mémoire, soit au moment de l’outofmemory (option -XX:+HeapDumpOnOutOfMemoryError), soit quand vous le souhaitez avec la jconsole (outil fourni par le jdk), en ayant lancé au préalable un garbage collector manuellement (depuis la jconsole également > onglet « memory » > bouton « perform gc »).

Comment demander à la JVM de lancer un Garbage Collector

Comment demander à la JVM de lancer un Garbage Collector



 
Une fois ce dump obtenu, il faut l’analyser, et regarder les objets de type classloader, et inspecter leurs attributs, notamment « loadDir », qui vous donnera le chemin de l’application lié au classloader.

Vous devez avoir un seul classloader pour chaque application déployé. Si tel n’est pas le cas, vous avez une fuite mémoire.

Vous avez maintenant trouvé le coupable, le mieux est alors de l’isoler dans le framework applicatif, en déchargeant toutes les applications et de redémarrer le framework.

Lancez alors la jconsole, et se positionner sur l’onglet ‘classes’ pour observer le nombre de classes chargées.

jconsole-deploy

Déploiement d'une application



 
Ensuite, déchargez l’application et demander un Garbage (n’hesitez pas à en faire plusieurs à la suite).

Déchargement d'une application

Déchargement d'une application



 
La vous êtes sur qu’il y a une fuite mémoire, car le nombre de classe chargées n’a pas diminué suite aux multiples garbages.

Maintenant, vous devrez modifier le code de l’application, puis à chaque fois vérifier si cela résout le problème en refaisant la manipulation que l’on vient de faire mais cette fois en constatant une baisse du nombre de classe chargé.

 

Par où commencer pour résoudre le problème ?

 
Soyons optimiste et disons nous que le problème vient de notre code et non d’une librairie externe que nous n’avons pas conçu nous-même.

D’une part, vérifier que lors du déchargement de notre application (par exemple dans la méthode « destroy() » d’une InitServlet), nous faisons correctement et totallement le ménage des objets complexes que nous utilisons.

Citons par exemple log4j avec ‘LogManager.shutdown()’, httpClient avec  ‘MultiThreadedHttpConnectionManager.shutdownAll()‘, JMX et le desenregistrement de nos mbeans, l’arrêt de notre pool de thread,  etc…

Ensuite, faites une recherche de tous les attributs static de l’application, et si possible, faites une méthode shutdown() si les attributs ou objets sont plutôt complexe et peuvent contenir beaucoup d’objets. Cela facilitera le travail du Garbage Collector, et surtout vérifier qu’il n’y a pas de cas problématique (voir plus haut) où un objet est référencé dans plus d’un attribut static.

 

Pendant que vous y êtes…

 
Vérifier également la gestion des threads lors des déploiments / déchargement de votre application.

Pour cela, utiliser la jconsole >> onglet ‘Threads’, et étudier la courbe ‘Live threads’. Effectuer plusieurs déploiements / déchargements consécutifs. La courbe ne doit pas monter, car alors cela signifie que des threads ne sont pas stoppé lors du déchargement.

Visualiser le nombre de threads

Visualiser le nombre de threads



 
Excellent document sur la ‘permanent generation space‘ et l’OutOfMemory : http://mediacast.sun.com/users/Frank.Kieviet/media/JavaOne07-BOF9982-PermGen.pdf

 

 

Analyse de la mémoire d’une application Java

14 septembre 2009 Laisser un commentaire

Lorsque vous voulez analyser la mémoire de votre programme java, le jdk 6 propose des outils puissants et relativement simples à utiliser.

Pré-requis :

Il vous faut le jdk5 minimum.
Il vous faut télécharger le plugin ‘eclipse memory analyzer‘ pour Eclipse, à installer depuis cet url http://download.eclipse.org/technology/mat/0.8/update-site/ à saisir dans le menu d’aide d’Eclipse, puis ‘mise à jour’.

La plupart des nouvelles fonctions de supervision sont regroupé via l’interface JMX, c’est pour cela qu’il est nécessaire d’activer JMX sur votre programme.

Pour cela, dans les options de ligne de commande du lancement de votre application, rajouter les options:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8084
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false

indiquant à la JVM d’activer JMX sans authentification et accessible via le port 8084 (que vous pouvez changer bien sur).

1ère étape : Obtenir un dump de la mémoire

Il existe plusieurs façons d’obtenir un dump :

  • Utilisation de la console JMX fournie avec le jdk

Dans un shell, tapez ‘jconsole‘.

login de la jconsole

login de la jconsole

Cochez ‘Remote Process‘, et saisir ‘localhost:8084‘ et cliquer sur ‘connect‘.
Ensuite dans l’onglet ‘MBeans‘, déroulez dans le menu de gauche la partie ‘com.sun.management.HotSpotDiagnostic.Operations‘ et sur la partie de droite, apparait une méthode ‘dumpHeap‘.

Dumper la mémoire

Dumper la mémoire

Le paramètre ‘P0‘ représente le chemin du fichier dump sur le disque à générer, et le paramètre ‘p1‘ doit rester à ‘true’, signifiant par cette valeur que nous voulons uniquement les objets vivants.
Appuyez sur le bouton ‘dumpHeap‘ et le fichier se génère à l’endroit spécifié.

  • Configurer notre programme java pour générer un dump lors d’une exception ‘OutOfMemoryError’.

Pour cela, il faut rajouter dans les options du programme ‘-XX:+HeapDumpOnOutOfMemoryError‘. Il générera un fichier de type « java_pidXXX.hprof » à la racine de votre application.

  • Utiliser l’outil ‘jmap‘ fourni par le jdk.

Dans un shell, tapez ‘jmap -dump:format=b,file=<fichier> <pid>‘ où <pid> est l’identifiant du process faisant tourner votre application et <fichier> est le chemin vers le fichier de dump sur le disque.
Sur un environnement 64bits, cette commande ne fonctionne pas, privilégiez alors JMX et la jconsole.

2eme étape : Analyser le dump

Il existe plusieurs façons d’analyser un dump, mais un fichier dump ne peut se lire avec un éditeur de texte, car c’est du binaire.

  • Utiliser le plugin ‘Memory analyzer‘ sous Eclipse.

Pour cela, il faut sélectionner la perspective du plugin, et ensuite cliquer sur le bouton pour ouvrir un fichier de dump.

Plugin memory analyser

Plugin memory analyser

Ensuite, il faut se laisser guider par le plugin. L’aide du plugin est très bien faite.
Pour commencer, dans le wizard qu’on nous propose, choisir ‘Leak Suspects report‘ et cliquez sur ‘Finish‘. Cette opération va déclencher une recherche des fuites mémoires possibles.

Fuite mémoire

Fuite mémoire

Le rapport ainsi produit nous indique clairement un problème avec des objets de type « Classloader » (problème typique dans des serveurs d’applications comme Tomcat).
Le gros du travail reste alors à faire, c’est à dire trouver pourquoi ces objets posent problème.
Le plugin propose également d’autres rapport intéressants:

Tableau de bord

Tableau de bord

Le rapport ‘Histogram‘ liste l’ensemble des classes de la mémoire, en nous précisant le nombre d’instances de chaque classe, le nombre d’octets pris par l’ensemble des objets de chaque classe (shallow heap) en comptabilisant les pointeurs directs uniquement, et enfin le nombre d’octets pris par l’ensemble des instances de classe en comptant cette fois en profondeur tous les objets contenus dans chaque instance (retained heap).

Par exemple, prenons le cas de la classe ArrayList. Cette classe contient principalement un tableau d’objets.
La ‘shallow heap’ d’un objet ArrayList est donc grosso modo équivalent à : taille du tableau * taille d’un pointeur (32 ou 64 bits suivant l’os).
La ‘retained heap’ d’un objet ArrayList correspond à la somme de tous les ‘shallow heap’ de l’ensemble des objets rattachés à cet objet. Prenons le cas d’un objet ArrayList de String, la retained heap est équivalent à : shallow heap de l’ArrayList + taille du tableau * retained heap d’un String.etc…

Histogram

Histogram

Le rapport ‘Dominator tree‘ liste l’ensemble des objets, ce qui nous permet de voir quels sont les objets qui prennent le plus de place en mémoire.

Dominator Tree

Dominator Tree

Ainsi, sur la capture ci dessus, on voit que l’objet ‘org.apache.catalina.loader.WebappClassLoader @ 0x68c1c60′ prend pas moins de 1,7 megaoctets à lui seul.
Lorsque l’on clique sur un objet, on peut voir dans l’onglet ‘attributes‘ les attributs de l’objet.

Enfin, le rapport ‘Duplicate classes‘ nous indique les mêmes classes qui ont été chargés en plusieurs exemplaire, ce qui permet de nous éclairer sur des optimisations à faire, et sur des problemes de classloader.

Quelques trucs et astuces sur l’utilisation de ce plugin :

Sur un objet ou une classe, appuyez sur le bouton droit de la souris et un menu apparait.
Si vous voulez connaître les classes qui référencent l’objet que vous avez sélectionné, choisissez ‘Show Objects by class > by incoming references‘.

Incoming reference

Incoming reference

Dans la capture, on peut voir que la classe ‘java.util.ArrayList‘ est utilisée dans la classe ‘java.beans.MethodDescriptor‘.

Si vous voulez connaître les objets que sont référencés par l’objet que vous avez sélectionné, choisissez ‘List Objects > with outgoing references‘.

Outgoing reference

Outgoing reference

Dans cette capture, on peut voir tous les objets en attributs direct de l’objet sélectionné, et voir la taille. Par exemple, on voit que c’est une ‘hashtable’ qui prend la majorité de la mémoire de l’objet sélectionné.

  • Utiliser l’outil ‘jhat‘ du jdk qui donne les mêmes informations que le plugin Eclipse mais ces informations parcours à l’aide d’un navigateur web, et l’ergonomie en patie. Les leaks ne sont pas indiqués, c’est à nous de les trouver.

Dans un shell, tapez ‘jhat -J-Xmx512m <fichier de dump sur le disque>‘. Je passe une valeur xmx car si le fichier de dump est gros, il faut de la mémoire pour l’analyser.
jhat analyse alors le dump, et lance un mini serveur web sur le port 7000. Il ne reste plus qu’à lancer un navigateur web à l’adresse ‘http://localhost:7000&rsquo; pour voir apparaître cet écran.

jhat

jhat

On retrouve certaines opérations disponibles dans le plugin eclipse, comme la partie ‘histogram‘.