397 votes

NullPointerException en Java sans StackTrace

J'ai eu des exemples de notre code Java qui a attrapé un NullPointerException mais lorsque j'essaie d'enregistrer le StackTrace (ce qui revient à appeler Throwable.printStackTrace() ), tout ce que j'obtiens est :

java.lang.NullPointerException

Quelqu'un d'autre a-t-il rencontré ce problème ? J'ai essayé de chercher sur Google "java null pointer empty stack trace" mais je n'ai rien trouvé de tel.

0 votes

Quel est le contexte ? Y a-t-il plusieurs fils impliqués ? J'ai eu des problèmes en essayant d'obtenir la trace de pile d'une exception dans un SwingWorker.

0 votes

Il n'est pas question ici de threading, mais simplement de Java.

1 votes

@Bozho - non - je ne sais pas encore comment reproduire le NullPointer.

500voto

Roland Illig Points 15357

Vous utilisez probablement la JVM HotSpot (à l'origine par Sun Microsystems, plus tard achetée par Oracle, faisant partie de l'OpenJDK), qui effectue beaucoup d'optimisation. Pour récupérer les traces de pile, vous devez passer l'option suivante à la JVM :

-XX:-OmitStackTraceInFastThrow

L'optimisation consiste à faire en sorte que lorsqu'une exception (typiquement un 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 suffisamment souvent, la trace de pile n'est plus imprimée, à la fois pour améliorer les performances et pour ne pas inonder le journal avec des traces de pile identiques.

Pour voir comment cela est mis en œuvre dans la JVM HotSpot, en obtenir une copie et rechercher la variable globale OmitStackTraceInFastThrow . La dernière fois que j'ai regardé le code (en 2019), il se trouvait dans le fichier graphKit.cpp .

1 votes

Merci pour le conseil. Savez-vous s'il y a des problèmes cachés à passer cette option (elle semble assez inoffensive tant que mon application ne lance pas une tonne d'exceptions) ?

0 votes

À ma connaissance, il n'y a pas de problèmes cachés. Lorsque vous regardez le code source de Hotspot, vous pouvez voir que cette option n'est utilisée qu'à un seul endroit (graphKit.cpp). Et cela me semble correct.

35 votes

J'ai pensé ajouter une information supplémentaire : lorsque la trace de la pile est optimisée, c'est parce qu'elle a été entièrement traitée au moins une fois : jawspeak.com/2010/05/26/…

65voto

Steven Schlansker Points 17463

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 de l'habituel

LOG.error("Some informative message", e);

par paresse ou peut-être tout simplement parce qu'ils n'y pensent pas. Ce qui est regrettable, c'est qu'il ne se comporte pas comme vous le pensez. L'API du logger prend en fait Object comme premier argument, et non une chaîne de caractères - et appelle ensuite toString() sur l'argument. Ainsi, au lieu d'obtenir une jolie trace de pile, il imprime simplement la toString - ce qui, dans le cas d'une NPE, est plutôt inutile.

C'est peut-être ce que vous vivez ?

0 votes

+1 : Cela expliquerait le comportement décrit, et vous n'êtes pas le seul à l'avoir découvert :)

4 votes

En fait, nous avons pour principe de ne jamais utiliser la première forme ci-dessus (LOG.error(exc) ;) - nous utilisons toujours la signature à 2 paramètres afin d'ajouter une déclaration descriptive aux journaux au lieu d'une simple trace de pile.

6 votes

Bien sûr, mais la politique ne signifie pas qu'elle est toujours exécutée correctement ! J'ai pensé que cela valait la peine d'être mentionné, au moins.

32voto

Matt Solnit Points 13528

Nous avons vu ce même comportement dans le passé. Il s'est avéré que, pour une raison étrange, si une NullPointerException se produisait plusieurs fois au même endroit dans le code, après un certain temps d'utilisation de Log.error(String, Throwable) cesserait d'inclure des traces de pile complètes.

Essayez de regarder plus loin dans votre journal. Vous trouverez peut-être le coupable.

EDIT : ce bogue semble pertinent, mais il a été corrigé il y a si longtemps qu'il n'en est probablement pas la cause.

3 votes

Le bogue est clos, mais l'option -XX:-OmitStackTraceInFastThrow est toujours nécessaire pour contourner l'optimisation des performances.

0 votes

C'est ce que j'ai souvent constaté ces derniers temps. Avez-vous des indices sur la cause de ce problème ou sur la façon de le résoudre ? Il se peut que le système d'enregistrement soit en place depuis des jours et que la cause réelle ait disparu, sans parler de la recherche fastidieuse...

5 votes

Pawel, avez-vous essayé le -XX:-OmitStackTraceInFastThrow Drapeau JVM suggéré par Joshua ? Voir aussi stackoverflow.com/a/2070568/6198 .

22voto

Benoît Guérout Points 776

Voici une explication : Hotspot a provoqué la perte des traces de pile des exceptions dans la production - et la solution

Je l'ai testé sur Mac OS X

  • java version "1.6.0_26"
  • Environnement d'exécution Java(TM) SE (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 spécifique, 12288 itérations (+fréquence ?) semble être la limite où la JVM a décidé d'utiliser l'exception préallouée...

11voto

Peter Lang Points 25877

exception.toString ne vous donne pas le StackTrace, il renvoie seulement

une brève description de ce projet 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

Utilice exception.printStackTrace pour afficher le StackTrace.

1 votes

Désolé, je me suis mal exprimé dans mon message initial. J'enregistre ces données via Log4J, qui utilise printStackTrace().

1 votes

Avez-vous essayé d'utiliser getStackTrace() pour vous assurer que le problème ne vient pas de votre enregistreur ?

1 votes

Si vous utilisez log4j, assurez-vous d'envoyer l'exception comme argument à la méthode log. Je publierai une réponse à ce sujet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X