J'ai eu des exemples de notre code Java attraper un NullPointerException
, mais quand j'essaie de journaliser le StackTrace (qui finit essentiellement par appeler Throwable.printStackTrace()
), tout ce que je reçois est:
java.lang.NullPointerException
Quelqu'un at-il rencontré ce? J'ai essayé de googler pour "trace de pile vide du pointeur java null" mais je n'ai rien trouvé de tel.
java
nullpointerexception
Edward Shtern
la source
la source
-XX:-OmitStackTraceInFastThrow
dans le dup: stackoverflow.com/questions/4659151/…Réponses:
Vous utilisez probablement la JVM HotSpot (à l'origine par Sun Microsystems, achetée plus tard par Oracle, une partie de l'OpenJDK), qui effectue beaucoup d'optimisation. Pour récupérer les traces de pile, vous devez passer l'option
-XX:-OmitStackTraceInFastThrow
à la JVM.L'optimisation est que lorsqu'une exception (généralement une NullPointerException) se produit pour la première fois, la trace de pile complète est imprimée et la JVM se souvient de la trace de pile (ou peut-être simplement de l'emplacement du code). Lorsque cette exception se produit assez souvent, la trace de pile n'est plus imprimée, à la fois pour obtenir de meilleures performances et pour ne pas inonder le journal avec des traces de pile identiques.
Pour voir comment cela est implémenté dans la machine virtuelle Java HotSpot, récupérez-en une copie et recherchez la variable globale
OmitStackTraceInFastThrow
. La dernière fois que j'ai regardé le code (en 2019), il était dans le fichier graphKit.cpp .la source
-XX:-OmitStackTraceInFastThrow
drapeau. Je n'ai pas encore confirmé si c'était la raison pour laquelle je n'imprimais pas non plus les traces de pile (par exemple, en utilisante.printStackTrace
), mais cela semble très probable. J'ai développé la réponse pour refléter cette découverte.Comme vous l'avez mentionné dans un commentaire, vous utilisez log4j. J'ai découvert (par inadvertance) un endroit où j'avais écrit
au lieu du typique
par paresse ou peut-être tout simplement pas y penser. La partie malheureuse de cela est qu'elle ne se comporte pas comme prévu. L'API de l'enregistreur prend en fait Object comme premier argument, pas une chaîne - puis il appelle toString () sur l'argument. Donc, au lieu d'obtenir la jolie jolie trace de pile, il imprime simplement la toString - ce qui dans le cas de NPE est assez inutile.
C'est peut-être ce que vous vivez?
la source
Nous avons vu ce même comportement dans le passé. Il s'est avéré que, pour une raison folle, si une exception NullPointerException se produisait au même endroit dans le code plusieurs fois, après un certain temps, l'utilisation
Log.error(String, Throwable)
cesserait d'inclure les traces de pile complètes.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 que ce n'est probablement pas la cause.
la source
-XX:-OmitStackTraceInFastThrow
drapeau JVM suggéré par Joshua? Voir aussi stackoverflow.com/a/2070568/6198 .Voici une explication: Hotspot a fait perdre aux traces de pile des exceptions en production - et le correctif
Je l'ai testé sur Mac OS X
Machine virtuelle serveur Java HotSpot (TM) 64 bits (build 20.1-b02-383, mode mixte)
Pour ce fragment de code spécifique, 12288 itérations (+ fréquence?) Semblent être la limite où la JVM a décidé d'utiliser l'exception préallouée ...
la source
exception.toString
ne vous donne pas le StackTrace, il ne renvoie queUtilisez
exception.printStackTrace
plutôt pour sortir le StackTrace.la source
getStackTrace()
pour vous assurer que le problème ne vient pas de votre enregistreur?Autre suggestion - si vous utilisez Eclipse, vous pouvez définir un point d'arrêt sur NullPointerException lui-même (dans la perspective de débogage, allez dans l'onglet "Points d'arrêt" et cliquez sur la petite icône qui contient un!)
Vérifiez à la fois les options "interceptées" et "non interceptées". Désormais, lorsque vous déclenchez le NPE, vous allez immédiatement atteindre le point d'arrêt et vous pouvez ensuite parcourir et voir exactement comment il est géré et pourquoi vous n'obtenez pas de trace de pile.
la source
toString()
renvoie uniquement le nom de l'exception et le message facultatif. Je suggère d'appelerpour vider le message, ou si vous avez besoin des détails sanglants:
la source
(Votre question n'est toujours pas claire quant à savoir si votre code appelle
printStackTrace()
ou si cela est effectué par un gestionnaire de journalisation.)Voici quelques explications possibles sur ce qui pourrait se produire:
L'enregistreur / gestionnaire utilisé a été configuré pour afficher uniquement la chaîne de message de l'exception, pas une trace de pile complète.
Votre application (ou une bibliothèque tierce) enregistre l'exception en utilisant
LOG.error(ex);
plutôt que la forme à 2 arguments (par exemple) de la méthode log4j Logger.Le message vient d'un endroit différent de celui où vous pensez qu'il est; par exemple, il s'agit en fait d'une méthode de bibliothèque tierce, ou de trucs aléatoires laissés par des tentatives antérieures de débogage.
L'exception en cours de journalisation a surchargé certaines méthodes pour masquer la trace de pile. Si tel 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 connectée.
Je pense que la dernière explication possible est assez improbable, mais les gens envisagent au moins de faire ce genre de chose pour "empêcher" l'ingénierie inverse. Bien sûr, cela ne réussit vraiment qu'à rendre la vie difficile aux développeurs honnêtes.
la source
Lorsque vous utilisez AspectJ dans votre projet, il peut arriver qu'un aspect masque sa partie de la trace de pile. Par exemple, aujourd'hui, j'ai eu:
Cette trace de pile a été imprimée lors de l'exécution du test via le surefire de Maven.
En revanche, lors de l'exécution du test dans IntelliJ, une trace de pile différente a été imprimée:
la source
Cela produira l'exception, utilisez uniquement pour déboguer, vous devriez mieux gérer vos exceptions.
la source