NullPointerException trace de stack non disponible sans agent de débogage

J’ai récemment trouvé un bug qui provoque une exception NullPointerException. L’exception est interceptée et consignée à l’aide d’une instruction slf4j standard. Code abrégé ci-dessous:

for(Action action : actions.getActions()) { try { context = action.execute(context); } catch (Exception e) { logger.error("...", e); break; } } 

Comme vous pouvez le voir, rien de compliqué. Cependant, de toutes les instructions de journalisation des exceptions que nous avons, celle-ci n’imprime pas une trace de stack. Tout ce qu’il imprime est le message (représenté par “…”) et le nom de la classe d’exception (java.lang.NullPointerException).

Étant donné que la trace de la stack sur une exception est chargée paresseuse, j’ai pensé qu’il y avait peut-être un problème de réorganisation des instructions et décidé d’appeler e.getStackTrace () avant l’instruction du journal. Cela n’a fait aucune différence.

J’ai donc décidé de redémarrer avec l’agent de débogage activé. Cependant, comme j’ai même attaché au processus, j’ai remarqué que les traces de la stack imprimaient maintenant. Ainsi, la présence de l’agent de débogage a rendu certaines informations de débogage supplémentaires disponibles.

J’ai depuis lors résolu la cause première de l’exception. Mais j’aimerais savoir pourquoi la trace de la stack n’était pas disponible sans un débogueur. Quelqu’un sait?

Clarification: ce n’est pas un problème de journalisation . Imaginez la même clause try / catch, mais dans la capture, j’imprime la valeur de:

 e.getStackTrace().length 

Sans débogueur, ceci affiche “0”, avec un débogueur, il imprime un nombre positif (9 dans ce cas).

Plus d’infos: cela se passe sur JDK 1.6.0_13, 64bit, amd64, linux 2.6.9

Est-il possible que ce code soit dans une boucle interne? Ensuite, le compilateur JIT comstack peut-être la stack d’appels pour cela en code natif, perdant ainsi les informations de la stack. Ensuite, lorsque vous connectez le débogueur, il désactive le JIT, rendant les informations à nouveau disponibles.

Les autres exceptions manuelles continuent d’afficher les informations car le JIT n’optimise pas.

Il semble que cela puisse parfois arriver pour d’autres à partir d’un commentaire dans le code source de cette classe à la ligne 102:

http://logging.apache.org/log4j/1.2/xref/org/apache/log4j/spi/LocationInfo.html

Avec l’indicateur JVM -XX: -OmitStackTraceInFastThrow, vous pouvez désactiver l’optimisation des performances de la machine virtuelle Java pour ce cas d’utilisation. Si ce paramètre est donné, ce qui désactive l’indicateur, le stacktrace sera disponible.

Pour plus d’informations, consultez les notes de publication suivantes:

“Le compilateur de la machine virtuelle du serveur fournit maintenant des traces de stack correctes pour toutes les exceptions intégrées” à froid “. Pour des raisons de performances, une telle exception peut être recompilée. Après la recompilation, le compilateur peut choisir une tactique plus rapide utilisant des exceptions préallouées qui ne fournissent pas de trace de stack Pour désactiver complètement l’utilisation des exceptions préallouées, utilisez ce nouvel indicateur: -XX: -OmitStackTraceInFastThrow. ” http://java.sun.com/j2se/1.5.0/relnotes.html

Je peux reproduire cela, mais cela semble un peu étrange que cela se produise quelque part dans votre Action.

Si vous appelez setStackTrace avec un tableau vide, seul le texte sera affiché.

  public class Fark { public static void main(Ssortingng[] args) { try { Fark.throwMe(args.length != 0); } catch (Exception e) { e.printStackTrace(); } } public static final void throwMe(boolean arg) throws Exception{ Exception e = new NullPointerException(); if (arg) { e.setStackTrace(new StackTraceElement[0]); } throw e; } } 

En cours d’exécution ….

 % java Fark java.lang.NullPointerException at Fark.throwMe(Fark.java:15) at Fark.main(Fark.java:5) % java Fark nothing java.lang.NullPointerException