Pregunta

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

java.lang.NullPointerException

¿Alguien más ha encontrado esto? He intentado googlear "java puntero nulo seguimiento de la pila vacía", pero no venir a través de algo como esto.

¿Fue útil?

Solución

probablemente se está utilizando el HotSpot JVM (originalmente por Sun Microsystems, más tarde comprada por Oracle, que forma parte de la OpenJDK), que realiza una gran cantidad de optimización. Para obtener las trazas de la pila hacia atrás, tiene que pasar la opción -XX:-OmitStackTraceInFastThrow a la JVM.

La optimización es que cuando una excepción (por lo general una NullPointerException) se produce por primera vez, se imprime la traza completa y la JVM recuerda el seguimiento de la pila (o tal vez sólo la ubicación del código). Cuando se produce con bastante frecuencia esta excepción, el seguimiento de pila no se imprime más, tanto para lograr un mejor rendimiento y no inundar el registro con trazas de pila idénticos.

Para ver cómo se implementa en el HotSpot JVM, agarrar una copia de la misma y la búsqueda de la OmitStackTraceInFastThrow variable global. La última vez que miré el código (en 2019), fue en el archivo graphKit.cpp .

Otros consejos

Como se ha mencionado en un comentario, usted está utilizando 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 se espera. La API registrador toma realmente objeto como el primer argumento, no una cadena - y luego se llama a toString () en el argumento. Así que en vez de conseguir el buen trazo bastante pila, sólo se imprime el toString -. Que en el caso de NPE es bastante inútil

Tal vez esto es lo que estás experimentando?

Hemos visto este mismo comportamiento en el pasado. Resultó que, por alguna extraña razón, si una NullPointerException se produjo en el mismo lugar en el código varias veces, después de un tiempo usando Log.error(String, Throwable) pararía incluyendo seguimientos de pila completo.

Trate de mirar más atrás en su registro. Es posible encontrar al culpable.

EDIT: este error sonidos relevante, pero lo arreglaron hace tanto tiempo que probablemente no es la causa.

A continuación se ofrece una explicación: hotspot causó excepciones a perder sus seguimientos de pila en la producción - y el arreglo

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

En 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 ...

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

exception.printStackTrace lugar a la salida de la StackTrace.

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)

Compruebe tanto la "atrapado" y "sin capturar" opciones - ahora, cuando se dispara la NPE, podrás punto de interrupción inmediatamente y, a continuación, puede pasar por todos y ver exactamente cómo se maneja y por qué usted no está consiguiendo un seguimiento de pila .

toString() sólo 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()

(Su pregunta todavía no está claro si su código está llamando printStackTrace() o esto se está haciendo por un manejador de registro.)

Aquí hay 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 alguna biblioteca de terceros) está registrando la excepción usando LOG.error(ex); lugar de la forma 2-argumento de (por ejemplo) el método Logger log4j.

  • El mensaje viene de un lugar diferente a donde cree que es; p.ej. en realidad proviene de algún método biblioteca de terceros, o algunas cosas al azar sobrante de los anteriores intentos 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 genuino, pero pasará algún subtipo costumbre de NPE o incluso alguna excepción sin conectar.

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 que en realidad sólo tiene éxito en hacer la vida más difícil para los desarrolladores honestos.

Cuando se utiliza AspectJ en su proyecto, puede ocurrir que algún aspecto oculta su porción de la traza de la pila. Por ejemplo, hoy he tenido:

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

Este seguimiento de la pila se imprimió cuando se ejecuta a través de la prueba segura 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)

Esta es la salida de la excepción, utilice sólo para depurar que usted debe manejar excepciones mejores.

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();
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top