Domanda

Ho avuto le istanze del nostro codice Java cattura un NullPointerException, ma quando provo ad accedere alla StackTrace (che finisce in pratica fino Throwable.printStackTrace() chiamare), tutto quello che ottiene è:

java.lang.NullPointerException

Qualcun altro ha incontrato questo? Ho provato googling per "java puntatore nullo analisi dello stack vuoto", ma non ho incontrato nulla di simile.

È stato utile?

Soluzione

Probabilmente si sta utilizzando la JVM HotSpot (originariamente da Sun Microsystems, successivamente acquistata da Oracle, una parte del OpenJDK), che svolge un sacco di ottimizzazione. Per ottenere i stack di nuovo, è necessario passare l'opzione -XX:-OmitStackTraceInFastThrow alla JVM.

L'ottimizzazione è che quando si verifica un'eccezione (tipicamente un NullPointerException) per la prima volta, la traccia stack completo viene stampato e la JVM ricorda la traccia dello stack (o forse solo la posizione del codice). Quando ciò si verifica un'eccezione abbastanza spesso, l'analisi dello stack non viene stampato più, sia per ottenere migliori prestazioni e non inondare il registro con tracce dello stack identici.

Per vedere come è implementato nel JVM HotSpot, prendere una copia di esso e cercare il OmitStackTraceInFastThrow variabile globale. L'ultima volta che ho guardato il codice (nel 2019), è stato nel file graphKit.cpp .

Altri suggerimenti

Come lei ha ricordato in un commento, si sta utilizzando log4j. Ho scoperto (involontariamente) un luogo in cui avevo scritto

LOG.error(exc);

al posto del tipico

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

per pigrizia o forse semplicemente non pensarci. La parte sfortunata di questo è che non si comporta come previsto. L'API logger prende effettivamente oggetto come primo argomento, non una stringa - e poi chiama toString () sull'argomento. Così, invece di ottenere il bel traccia bella pila, si limita a stampare il toString -. Che nel caso di NPE è abbastanza inutile

Forse questo è quello che stai vivendo?

Abbiamo visto questo stesso comportamento in passato. Si è scoperto che, per qualche ragione folle, se un NullPointerException si è verificato nello stesso luogo nel codice più volte, dopo un po 'utilizzando Log.error(String, Throwable) si fermava tra cui tracce di stack completo.

Prova a guardare più indietro nel registro. Si può trovare il colpevole.

Modifica questo bug suoni rilevante, ma è stato risolto molto tempo fa non è probabilmente la causa.

Ecco una spiegazione: Hotspot causato eccezioni per perdere le loro tracce dello stack in produzione - e la correzione

Ho testato su 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) a 64 bit di server VM (build 20.1-b02-383, modalità mista)

    Object string = "abcd";
    int i = 0;
    while (i < 12289) {
        i++;
        try {
            Integer a = (Integer) string;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

Per questo specifico frammento di codice, 12288 iterazioni (+ frequenza?) Sembra essere il limite in cui JVM ha deciso di utilizzare eccezione preallocato ...

exception.toString non ti dà la StackTrace, restituisce solo

  

una breve descrizione di questa Throwable.   Il risultato è la concatenazione di:

* the name of the class of this object
* ": " (a colon and a space)
* the result of invoking this object's getLocalizedMessage() method

exception.printStackTrace invece uscita StackTrace.

suggerimento alternativo - se si sta utilizzando Eclipse, è possibile impostare un punto di interruzione NullPointerException stesso (! Nella prospettiva di debug, passare alla scheda "Punti di interruzione" e cliccare sulla piccola icona che ha una in esso)

Controlla sia il "catturato" e le opzioni "non rilevati" - Ora, quando si attiva la NPE, si breakpoint immediatamente e si può quindi passo e vedere esattamente come viene gestito e perché non stai ricevendo una traccia dello stack .

toString() restituisce solo il nome eccezione e il messaggio opzionale. Vorrei suggerire di chiamare

exception.printStackTrace()

per scaricare il messaggio, o se avete bisogno di dettagli scabrosi:

 StackTraceElement[] trace = exception.getStackTrace()

(La tua domanda è ancora chiaro se il codice sta chiamando printStackTrace() o questo è stato fatto da un gestore di registrazione.)

Ecco alcune possibili spiegazioni su ciò che potrebbe accadere:

  • Il registratore / gestore utilizzato è stato configurato per solo uscita stringa di messaggio del un'eccezione, non una traccia stack completo.

  • L'applicazione (o qualche libreria di terze parti) sta registrando l'eccezione utilizzando LOG.error(ex); piuttosto che la forma 2-argomento (per esempio) il metodo di log4j Logger.

  • Il messaggio viene da un posto diverso da dove si pensa che è; per esempio. in realtà è venuta un po 'di metodo di libreria di terze parti, o di alcune cose a caso rimasto da precedenti tentativi di debug.

  • L'eccezione che viene registrato è sovraccaricato alcuni metodi per oscurare la stacktrace. Se questo è il caso, l'eccezione non sarà un vero e proprio NullPointerException, ma sarà un po 'di sottotipo usanza di NPE o anche qualche eccezione non collegati.

Credo che l'ultimo possibile spiegazione è piuttosto improbabile, ma la gente fare almeno contemplo fare questo genere di cose per "prevenire" reverse engineering. Certo che riesce veramente solo nel rendere la vita difficile per gli sviluppatori onesti.

Quando si utilizza AspectJ nel progetto, può accadere che qualche aspetto nasconde la sua porzione della traccia dello stack. Per esempio, oggi ho avuto:

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

Questa analisi dello stack è stato stampato quando si esegue il test tramite infallibile di Maven.

D'altra parte, quando si esegue il test in IntelliJ, una diversa traccia dello stack è stato stampato:

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)

Questa uscita volontà l'eccezione, utilizzare solo per eseguire il debug si dovrebbe gestire le eccezioni che si migliori.

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();
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top