Archives pour la catégorie ‘Développement’

Java : analyser le heap d’une application

La version 1.6 de la machine Java de Sun intégre un outil permettant d’analyser le heap d’une application : jhat. Il permet par exemple de vérifier quelles sont les instances vivantes des objets dans le heap, le nombre de créations d’instances pour un object donné, un historique de création … Bref, un outil simple pour profiler un minimum son soft et éviter les messages de ce genre (c’est pour l’exemple) :

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

En premier lieu sous Mac OS X, cet outil ne fonctionne pas out of the box, il faut installer un moteur JavaScript (celui d’Apple lance une exception au lancement de jhat). Pour installer un autre moteur JS, téléchargez les 2 archives suivantes :
– JSR-223’s engines : https://scripting.dev.java.net/files/documents/4957/37593/jsr223-engines.zip
– Rhino : http://www.mozilla.org/rhino/download.html

$ sudo cp ~/Desktop/jsr223-engines/javascript/build/js-engine.jar /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/ext/
$ sudo cp ~/Desktop/rhino1_7R2/js.jar /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/lib/ext/

Le nouveaux moteur JS Rhino doit à présent être listé par jrunscript :

$ /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/jrunscript -q
Language EmbeddedECMAScript 1.6 implemention "Mozilla Rhino" 1.6 release 2
Language AppleScript 2.0.1 implemention "AppleScriptEngine" 1.0
Language ECMAScript 1.6 implemention "Mozilla Rhino" 1.6R7

Pour lancer l’analyse du heap d’une application, il est nécessaire de récupérer son PID par jps, pour le passer à jmap qui va dumper le heap dans un fichier. Une fois créé, on peut l’analyser avec jhat :

$ /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Commands/jps
22746 Jps
22716 Application
45737
$ /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Commands/jmap -dump:format=b,file=dump.dat 22716
Dumping heap to /Users/bhuisgen/dump.dat ...
Heap dump file created
$ /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Commands/jhat -J-Xmx512m dump.dat
Reading from dump.dat...
Dump file created Sun May 17 18:22:24 CEST 2009
Snapshot read, resolving...
Resolving 160010 objects...
Chasing references, expect 32 dots................................
Eliminating duplicate references................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

Rendez-vous @ http://127.0.0.1:7000 pour consulter les résultats : nombres d’instances créées, histogramme de création, et un query browser OQL qui permet de faire ses propres requêtes d’analyse (à tester absolument).

Java : analyse de code et détection de bugs

S’il y a bien un logiciel à conserver dans sa boite à outils, il s’agit d’un analyseur de code. En phase de stabilisation d’un de mes logiciels, j’en ai profité pour passer un coup de FindBugs!, l’analyseur et détecteur de bugs open-source pour Java. Il opère directement sur le byte-code à la recherche d’erreurs de programmation et si les sources sont disponibles, il marque son  endroit exact. Il dispose de son propre frontend graphique, mais un plugin Eclipse existe. L’intégration à un projet peut également se faire par le biais d’une tâche Ant.

Je me suis donc retrouvé avec à peu près 80 problèmes tous types confondus (sur les 40 000 lignes du projet, je trouve çà honnête), sachant qu’il y a toujours des faux-positifs (au nombre de 60). Pêle-mêle, il a réussi à détecter :

  • des nettoyages de ressources inutiles dans des blocs de traitement d’exception.
  • des itérateurs inadaptés par exemple lors d’une itération de Map, en me conseillant l’utilisation du bon (screenshot 1).
  • des problèmes de synchronisation d’ accès concurrents.
  • un bloc synchronized vide, dans mon cas un faux-positif (screenshot 2).
  • un appel à wait () hors d’une boucle d’itération, idem faux-positif.
  • l’utilisation de variables inutiles.

Bref, l’outil relève des faux-positifs – c’est quelque peu obligatoire – mais son utilité n’en n’est pas atteinte !

Site officiel : http://findbugs.sourceforge.net/
Source de téléchargement du plugin Eclipse : http://findbugs.cs.umd.edu/eclipse/
Autres outils du même type : MPD, CheckStyle…

Java : loguer les exceptions avec un stacktrace

Un petit bout de code utile pour tout programme de type démon/serveur et qui permet d’enregistrer dans un fichier journal (cf. API java.util.logging) toute exception non gérée, en particulier avec son stacktrace complet, tel que Java le produirait en console :

private final static Logger m_logger = Logger.getLogger ("package.MyClass");

try
{
    [...]
}
catch (Exception exception)
{
    StringBuilder stackTrace = new StringBuilder ("exception during execution: " +
        exception.getMessage ());

    for (StackTraceElement element : exception.getStackTrace ())
    {
        stackTrace.append ("\n\tat " + element.getClassName ()
                + ":" + element.getMethodName () + "("
                + element.getFileName () + ":"
                + element.getLineNumber () + ")");
    }

    m_logger.log (Level.SEVERE, stackTrace.toString ());
}

Exemple de sortie :

2 mai 2009 18:51:26 fr.hbis.ircs.Client parse
GRAVE: exception during command execution 'JOIN': fr.hbis.ircs.Channel.create(Ljava/lang/String;
Ljava/lang/String;)Lfr/hbis/ircs/Channel;
at fr.hbis.ircs.commands.Join:doCommand(Join.java:130)
at fr.hbis.ircs.commands.Join:execute(Join.java:64)
at fr.hbis.ircs.Client:parse(Client.java:158)
at fr.hbis.ircs.Client:read(Client.java:127)
at fr.hbis.ircs.nio.MessageTask:doProcess(MessageTask.java:253)
at fr.hbis.ircs.nio.MessageTask:doRead(MessageTask.java:197)
at fr.hbis.ircs.nio.MessageTask:doTask(MessageTask.java:152)
at fr.hbis.ircs.lib.nio.task.TaskBase:run(TaskBase.java:102)
at java.util.concurrent.ThreadPoolExecutor$Worker:runTask(ThreadPoolExecutor.java:885)
at java.util.concurrent.ThreadPoolExecutor$Worker:run(ThreadPoolExecutor.java:907)
at fr.hbis.ircs.lib.nio.worker.DefaultWorkerThread:run(DefaultWorkerThread.java:123)

Sympa, on en perd plus une miette.

Java : pense-bête JVM & options d’exécution

Un petit pense-bête concernant les différentes options d’exécution de la JVM étant donné que j’arrive pas les retenir.

Journalisation avec fichier de configuration custom pour l’API java.util.logging :

java [...] -Djava.util.logging.config.file=./logging.properties [...]

Monitoring avec jconsole :

  • en local :
java [...] -Dcom.sun.management.jmxremote [...]
  • à distance :
java [...] -Dcom.sun.management.jmxremote \
        -Dcom.sun.management.jmxremote.port=8001 \
        -Dcom.sun.management.jmxremote.authenticate=false \
        -Dcom.sun.management.jmxremote.ssl=false [...]

Remote debug JDPA :

  • avec JVM < 5.0 :
java [...] -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="8000" [...]
  • avec JVM >= 5.0 :
java [...] -agentlib:jdwp=transport=dt_socket,server=y,address="8000" [...]

Eclipse : Remote debugging avec JDPA

Parfois, il est indispensable de tester son application sous un environnement précis. Si cela ne tourne pas rond, un debug est nécessaire. Pour conserver les mêmes conditions d’exécution, un debug distant depuis son IDE est possible. Le principe est qu’une connexion réseau est faite entre le frontend du débogueur (IDE) et un backend au niveau de la JVM (JDPA, Java Debug Architecture). Deux méthodes sont possibles  :

  • « Socket attach » : une socket est en écoute au niveau de la JVM. L’IDE va s’y connecter pour contrôler le flux d’exécution et récupérer les informations de debug.
  • « Socket listen » : une socket est en écoute sur la machine de développement. Dans ce cas, la JVM s’y connecte pour ensuite être contrôlée.

Le choix entre les 2 méthodes dépend du filtrage réseau présent entre les 2 postes. Des options spécifiques sont donc à fournir à la JVM dont l’adresse IP / port de la socket et la méthode de remote debug.

Avec Eclipse, un remote debug par socket attach se fait ainsi :

  1. Compilation des sources avec les options de debug (sans blague)
  2. Déploiement / lancement de l’application sur la machine de test :
    java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 [...]
    
  3. Lancer l’application depuis l’IDE avec une configuration de remote debug en précisant l’IP + port du serveur d’exécution : menu Run -> Debug … -> Remote Java Application.

Le reste s’effectue comme un debug traditionnel.

 

Git : package binaire Mac OS X

Un package binaire de Git pour Mac OS X est disponible à cet adresse :

http://code.google.com/p/git-osx-installer/downloads/list?can=3

Eclipse 3.5 : portage SWT sous Cocoa

La prochaine version 3.5 d’Eclipse apportera le portage de la librairie graphique SWT sous Cocoa (Mac OS X 10.5 uniquement).

Pour tester une version de développement, cliquez ici.

Haut de page