2010-03-09 22 views
227

he tenido casos de nuestra coger un código Java NullPointerException, pero cuando intento acceder al StackTrace (que básicamente termina llamando Throwable.printStackTrace()), todo lo que consigo es:NullPointerException en Java sin StackTrace

java.lang.NullPointerException 

¿Alguien más se ha encontrado con esto? Intenté buscar en Google "rastro de pila vacía de puntero java" pero no encontré nada como esto.

+0

Cuál es el contexto? ¿Hay múltiples hilos involucrados? He tenido problemas al tratar de obtener el rastro de la pila de una excepción en un SwingWorker. –

+0

No hay enhebrado aquí, simplemente antiguo Java. –

+0

intenté un depurador? – Bozho

Respuesta

264

Probablemente esté utilizando Sun JVM, que realiza una gran cantidad de optimización. Para recuperar los restos de la pila, debe pasar la opción -XX:-OmitStackTraceInFastThrow a la JVM.

+1

Gracias por la sugerencia. ¿Alguna idea de si hay trampas escondidas para pasar esta opción (parece bastante inocua siempre que mi aplicación no arroje una tonelada de excepciones)? –

+0

No hay trampas ocultas que yo sepa. Cuando miras el código fuente del Hotspot, puedes ver que esta opción solo se usa en un lugar (graphKit.cpp). Y eso se ve bien para mí. –

+27

Pensé que agregaría la información adicional que cuando se optimiza el seguimiento de la pila, es porque se ha manejado por completo al menos una vez: http://jawspeak.com/2010/05/26/hotspot-caused-exceptions -to-lose-their-stack-traces-in-production-and-the-fix / – sharakan

9

exception.toString no le da la StackTrace, que sólo devuelve

una breve descripción de esta throwable. El resultado es la concatenación de:

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

Uso exception.printStackTrace lugar a la salida de la StackTrace.

+0

Disculpa, me equivoqué en mi publicación original. Estoy registrando estos a través de Log4J, que usa printStackTrace(). –

+1

¿Ha intentado usar 'getStackTrace()' para asegurarse de que el problema no está con su registrador? –

+1

Si está utilizando log4j, asegúrese de enviar la excepción como parte del argumento al método de registro. Voy a publicar una respuesta con eso. –

1

toString() solo devuelve el nombre de la excepción y el mensaje opcional. Yo sugeriría llamando

exception.printStackTrace() 

para volcar el mensaje, o si necesita los detalles morbosos:

StackTraceElement[] trace = exception.getStackTrace() 
+0

Ver arriba - Me equivoqué - Estoy usando printStackTrace(). –

0

Esta es la salida de la excepción, utilice exclusivamente para depurar debe manejar excepciones que mejor.

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(); 
    } 
48

Como mencionaste en un comentario, estás usando log4j. He descubierto (sin querer) un lugar en el que había escrito

LOG.error(exc); 

en lugar de la típica

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

por pereza o tal vez simplemente no pensar en ello. La parte desafortunada de esto es que no se comporta como esperabas. La API de registrador realmente toma Object como el primer argumento, no una cadena, y luego llama aString() en el argumento. Entonces, en lugar de obtener el bonito y bonito seguimiento de pila, simplemente imprime el toString, que en el caso de NPE es bastante inútil.

Quizás esto es lo que estás experimentando?

+0

+1: Esto explicaría el comportamiento descrito, y usted no es el único que descubrió esto :) –

+2

En realidad, tenemos una política estándar de no utilizar el primer formulario anterior (LOG.error (exc);) - siempre usamos la firma de 2 parámetros para que agreguemos una declaración descriptiva a los registros en lugar de solo una pila de pila sin procesar. –

+4

¡Claro, pero la política no significa que siempre se ejecuta correctamente! Pensé que valía la pena mencionar, al menos. –

4

sugerencia alternativa - si estás usando Eclipse, podría establecer un punto de interrupción en sí NullPointerException (! En la perspectiva de depuración, vaya a la pestaña "puntos de ruptura" y hacer clic en el pequeño icono que tiene un en ella)

Comprueba las opciones "capturadas" y "no detectadas": ahora cuando disparas el NPE, de inmediato lo rompes y luego puedes ver cómo exactamente se maneja y por qué no obtienes un seguimiento de pila.

1

(Su pregunta aún no está clara si su código está llamando al printStackTrace() o si lo está haciendo un manejador de registro.)

Estas son algunas posibles explicaciones sobre lo que podría estar sucediendo:

  • El registrador/controlador que se utiliza se ha configurado para la salida única cadena del mensaje de la excepción, no una traza completa.

  • Su aplicación (o una biblioteca de terceros) está registrando la excepción utilizando LOG.error(ex); en lugar de la forma de 2 argumentos (por ejemplo) del método Log4j Logger.

  • El mensaje viene de un lugar diferente al que cree que es; p.ej. en realidad viene algún método de biblioteca de terceros, o algunas cosas aleatorias sobrantes de intentos anteriores de depurar.

  • La excepción que se está registrando ha sobrecargado algunos métodos para ocultar el stacktrace. Si ese es el caso, la excepción no será una NullPointerException genuina, sino que será un subtipo personalizado de NPE o incluso alguna excepción no conectada.

creo que la última explicación posible es muy poco probable, pero la gente lo menos contemplar haciendo este tipo de cosas "prevenir" ingeniería inversa. Por supuesto, solo tiene éxito al dificultar la vida de los desarrolladores honestos.

20

Hemos visto este mismo comportamiento en el pasado. Resultó que, por algún loco motivo, si una NullPointerException ocurría en el mismo lugar en el código varias veces, después de un tiempo usando Log.error(String, Throwable) se detendrían incluidos los rastros de pila completa.

Intente mirar más atrás en su registro. Puede encontrar al culpable.

EDIT:this bug sonidos relevantes, pero se fijó hace tanto tiempo que probablemente no es la causa.

+1

El error está cerrado, pero el indicador -XX: -OmitStackTraceInFastThrow sigue siendo necesario para solucionar la optimización del rendimiento. –

+0

He estado viendo esto recientemente. ¿Alguna pista sobre qué podría estar causando esto o cómo solucionarlo? El sistema de registro puede haber estado activo durante días, y la causa real se ha girado, sin importar la tediosa búsqueda ... –

+2

Pawel, ¿has probado la bandera '-XX: -OmitStackTraceInFastThrow' JVM sugerida por Joshua? Ver también http://stackoverflow.com/a/2070568/6198. –

13

Aquí es una explicación: Hotspot caused exceptions to lose their stack traces in production – and the fix

Lo he probado en 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) de 64 bits del servidor VM (build 20.1-b02-383, modo mixto)

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

Para este fragmento de código específica, 12288 iteraciones (+ frecuencia?) Parece ser el límite en el que la JVM ha decidido utilizar excepción preasignado ...

0

Cuando está utilizando AspectJ en su proyecto, puede suceder que algún aspecto oculte su parte del seguimiento de la pila.Por ejemplo, hoy tuve:

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

Este rastro de pila se imprimió al ejecutar la prueba a través del seguro de Maven.

Por otro lado, cuando se ejecuta la prueba de IntelliJ, un seguimiento de pila diferente fue impreso:

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) 
Cuestiones relacionadas