NullPointerException en Java sans Stactrace
j'ai eu des instances de notre code Java attraper un NullPointerException
, mais quand j'essaie de log la chaîne de stockage (qui se termine essentiellement par appeler Throwable.printStackTrace()
), tout ce que je reçois est:
java.lang.NullPointerException
quelqu'un d'autre A rencontré ce? J'ai essayé de googler pour "java null pointer empty stack trace" mais je n'ai rien trouvé de tel.
10 réponses
vous utilisez probablement le Sun JVM, qui effectue beaucoup d'optimisation. Pour récupérer les traces de la pile, vous devez passer l'option -XX:-OmitStackTraceInFastThrow
à la JVM.
JVMs OpenJDK modernes (1,8 et plus?) semblent accepter le -XX:-OmitStackTraceInFastThrow
drapeau (et ont stack-trace d'optimisation activée par défaut).
comme vous l'avez mentionné dans un commentaire, vous utilisez log4j. J'ai découvert (par inadvertance) un endroit où j'avais écrit
LOG.error(exc);
au lieu du "151930920 typique"
LOG.error("Some informative message", e);
par paresse ou peut-être ne pas y penser. Ce qui est regrettable, c'est qu'il ne se comporte pas comme prévu. L'API logger prend en fait Object comme premier argument, pas une chaîne de caractères - et appelle ensuite toString() sur l'argument. Ainsi, au lieu de en obtenant la jolie trace de pile, il imprime juste le toString - qui dans le cas de NPE est assez inutile.
C'est peut-être ce que vous vivez?
Nous avons vu ce même comportement dans le passé. Il s'est avéré que, pour une raison folle, si une NullPointerException se produisait au même endroit dans le code plusieurs fois, après un certain temps en utilisant Log.error(String, Throwable)
cesserait d'inclure des traces de pile complète.
Essayez de regarder plus loin dans votre journal. Vous pouvez trouver le coupable.
EDIT: ce bug semble pertinent, mais il a été corrigé Il y a si longtemps probablement pas la cause.
Voici une explication : Hotspot fait des exceptions pour perdre leurs traces de cheminée dans la production – et le fix
Je l'ai testé sur Mac OS X
- version java "1.6.0_26"
- Java(TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511)
-
Java HotSpot (TM) 64-Bit Server VM (build 20.1-b02-383, mixed mode)
Object string = "abcd"; int i = 0; while (i < 12289) { i++; try { Integer a = (Integer) string; } catch (Exception e) { e.printStackTrace(); } }
pour ce fragment de code, 12288 itérations (+fréquence?) semble être la limite où JVM a décidé de recourir à l'exception préallouée...
exception.toString
ne vous donne pas le Stactrace, il retourne seulement
une brève description de ce lancer. Le résultat est la concaténation de:
* the name of the class of this object * ": " (a colon and a space) * the result of invoking this object's getLocalizedMessage() method
utilisez exception.printStackTrace
au lieu de sortir le StackTrace.
suggestion alternative - si vous utilisez Eclipse, vous pouvez définir un point de rupture sur NullPointerException lui-même (dans la perspective de débogage, allez à l'onglet "points de rupture" et cliquez sur la petite icône qui a un ! en)
Cochez à la fois les options" pris "et" non pris " - maintenant, lorsque vous activez le NPE, vous cassez immédiatement et vous pouvez alors passer à travers et voir comment exactement il est manipulé et pourquoi vous ne recevez pas une trace de pile.
toString()
renvoie uniquement le nom de l'exception et le message Facultatif. Je suggère d'appeler
exception.printStackTrace()
pour vider le message, ou si vous avez besoin des détails sanglants:
StackTraceElement[] trace = exception.getStackTrace()
(votre question n'est toujours pas claire si votre code appelle printStackTrace()
ou si cela est fait par un gestionnaire de journalisation.)
voici quelques explications possibles sur ce qui pourrait se passer:
-
L'enregistreur / gestionnaire utilisé a été configuré pour ne produire que la chaîne de messages de l'exception, et non une trace complète de la pile.
-
votre demande (ou un tiers library) enregistre l'exception en utilisant
LOG.error(ex);
plutôt que la forme à 2 arguments de (par exemple) la méthode Logger log4j. -
le message vient d'un endroit différent de celui où vous pensez qu'il est; par exemple, il vient en fait d'une méthode de bibliothèque tierce partie, ou de quelques trucs aléatoires laissés par des tentatives précédentes de débogage.
-
l'exception qui est journalisée a surchargé certaines méthodes pour obscurcir le stactrace. Si c'est le cas, l'exception ne sera pas une véritable NullPointerException, mais sera un sous-type personnalisé de NPE ou même une exception non liée.
je pense que la dernière explication possible est assez peu probable, mais les gens envisagent au moins de faire ce genre de chose pour" empêcher " la rétroingénierie. Bien sûr, il ne réussit vraiment à rendre la vie difficile pour les développeurs honnêtes.
cela affichera L'Exception, n'utilisez que pour déboguer vous devriez mieux gérer vos exceptions.
import java.io.PrintWriter;
import java.io.StringWriter;
public static String getStackTrace(Throwable t)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw, true);
t.printStackTrace(pw);
pw.flush();
sw.flush();
return sw.toString();
}
lorsque vous utilisez AspectJ dans votre projet, il peut arriver qu'un aspect cache sa partie de la trace de la pile. Par exemple, aujourd'hui j'ai eu:
java.lang.NullPointerException:
at com.company.product.MyTest.test(MyTest.java:37)
cette trace de pile a été imprimée lors de l'exécution du test via le surefire de Maven.
par contre, lors de l'exécution du test dans IntelliJ, une trace différente de pile a été imprimée:
java.lang.NullPointerException
at com.company.product.library.ArgumentChecker.nonNull(ArgumentChecker.java:67)
at ...
at com.company.product.aspects.CheckArgumentsAspect.wrap(CheckArgumentsAspect.java:82)
at ...
at com.company.product.MyTest.test(MyTest.java:37)