Question

J'ai eu des cas de notre code Java attraper un NullPointerException, mais quand je tente de me connecter le StackTrace (qui se termine essentiellement par appeler Throwable.printStackTrace()), tout ce que je reçois est:

java.lang.NullPointerException

Quelqu'un at-il rencontré ce? J'ai essayé googler « pointeur java null trace de la pile vide », mais n'a pas rencontré quelque chose comme ça.

Était-ce utile?

La solution

Vous utilisez probablement la machine virtuelle Java HotSpot (à l'origine par Sun Microsystems, puis racheté par Oracle, une partie de l'OpenJDK), qui effectue beaucoup d'optimisation. Pour obtenir les traces de la pile de retour, vous devez passer l'option -XX:-OmitStackTraceInFastThrow à la machine virtuelle Java.

L'optimisation est que, quand une exception (typiquement un NullPointerException) se produit pour la première fois, la pleine trace de pile est imprimé et la machine virtuelle Java se souvient de la trace de la pile (ou peut-être juste l'emplacement du code). Lorsque cette exception se produit assez souvent, la trace de la pile n'est pas imprimé plus, à la fois pour obtenir de meilleures performances et de ne pas inonder le journal avec des traces de pile identiques.

Pour voir comment cela est mis en œuvre dans la machine virtuelle Java HotSpot, saisir une copie et la recherche de la OmitStackTraceInFastThrow variable globale. La dernière fois que je regardais le code (en 2019), il était dans le fichier graphKit.cpp .

Autres conseils

Comme vous l'avez mentionné dans un commentaire, vous utilisez log4j. J'ai découvert (par inadvertance) un endroit où je l'avais écrit

LOG.error(exc);

au lieu du type

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

par paresse ou peut-être tout simplement pas y penser. Le malheur est qu'il ne se comporte pas comme prévu. L'API enregistreur prend en fait l'objet comme premier argument, pas une chaîne - et il appelle toString () sur l'argument. Ainsi, au lieu d'obtenir la belle jolie trace de la pile, il se contente d'afficher la toString -. Qui, dans le cas de NPE est assez inutile

Peut-être est ce que vous vivez?

Nous avons vu ce même comportement dans le passé. Il est avéré que, pour une raison folle, si un NullPointerException est survenu au même endroit dans le code plusieurs fois, après un certain temps à l'aide Log.error(String, Throwable) arrêterait notamment des traces complètes de la pile.

Essayez de regarder plus loin en arrière dans votre journal. Vous pouvez trouver le coupable.

EDIT: ce bug sons pertinente, mais il a été fixé si longtemps, il est probablement pas la cause.

Voici une explication: Hotspot a causé des exceptions à perdre leurs traces de pile dans la production - et le correctif

Je l'ai testé sous Mac OS X

  • java version "1.6.0_26"
  • Java (TM) SE Runtime Environment (build 1.6.0_26-b03-383-11A511)
  • Java HotSpot (TM) 64-Bit serveur VM (build 20,1 b02-383, mode mixte)

    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ù JVM a décidé d'utiliser ... exception préaffecté

exception.toString ne vous donne pas le StackTrace, il retourne uniquement

  

une brève description de ce throwable.   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 la sortie StackTrace.

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 a un dedans)

Vérifier à la fois la « prise » et les options « uncaught » - maintenant lorsque vous déclenchez la NPE, vous immédiatement et vous pouvez point d'arrêt alors l'étape à travers et voir exactement comment il est géré et pourquoi vous n'êtes pas obtenir une trace de la pile .

toString() ne retourne que le nom de l'exception et le message en option. Je suggère d'appeler

exception.printStackTrace()

pour vider le message, ou si vous avez besoin des détails sordides:

 StackTraceElement[] trace = exception.getStackTrace()

(Votre question ne sait pas encore si votre code appelle printStackTrace() ou cela se fait par un gestionnaire de l'exploitation forestière.)

Voici quelques explications possibles sur ce qui pourrait se produire:

  • L'enregistreur / gestionnaire utilisé a été configuré pour délivrer en sortie uniquement la chaîne de message de l'exception et non une trace complète de la pile.

  • Votre application (ou d'une bibliothèque tierce) se connecte à l'exception en utilisant LOG.error(ex); plutôt que la forme 2-argument (par exemple) du procédé de l'enregistreur log4j.

  • Le message provient d'un endroit différent où vous pensez qu'il est; par exemple. il est en fait venir une méthode de bibliothèque tierce, ou des choses au hasard qui reste des tentatives antérieures de débogage.

  • L'exception qui est connecté a surchargé des méthodes pour masquer le stacktrace. Si tel est le cas, l'exception ne sera pas un véritable NullPointerException, mais un certain sous-type personnalisé de NPE ou même une exception non connecté.

Je pense que la dernière explication possible est assez peu probable, mais les gens ne au moins faire ce genre contemple de chose à « empêcher » l'ingénierie inverse. Bien sûr, il ne réussit vraiment à rendre la vie difficile pour les développeurs honnêtes.

Lorsque vous utilisez AspectJ dans votre projet, il peut arriver que certains aspects cache sa partie de la trace de la pile. Par exemple, aujourd'hui j'avais:

java.lang.NullPointerException:
  at com.company.product.MyTest.test(MyTest.java:37)

Cette trace de la pile a été imprimé lors du test via le surefire de Maven.

D'autre part, lors de l'exécution du test en IntelliJ, a été imprimé une trace de pile différent:

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)

Affichera l'exception, utilisez uniquement pour vous debug, vous gérer les exceptions mieux.

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();
    }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top