NullPointerException-Stack-Trace ohne Debug-Agent nicht verfügbar

Lesezeit: 4 Minuten

Benutzer-Avatar
merkudat

Ich habe kürzlich einen Fehler gefunden, der eine NullPointerException verursacht. Die Ausnahme wird mit einer standardmäßigen slf4j-Anweisung abgefangen und protokolliert. Gekürzter Code unten:

for(Action action : actions.getActions()) {
    try {
        context = action.execute(context);
    } catch (Exception e) {
        logger.error("...", e);
        break;
    }
}

Wie Sie sehen können, nichts Besonderes. Von all den Ausnahmeprotokollierungsanweisungen, die wir haben, druckt jedoch nur diese keinen Stack-Trace. Alles, was es ausgibt, ist die Nachricht (dargestellt als “…”) und der Name der Ausnahmeklasse (java.lang.NullPointerException).

Da der Stack-Trace bei einer Ausnahme verzögert geladen wird, dachte ich, dass es möglicherweise ein Problem mit der Neuordnung von Anweisungen gibt, und entschied mich, e.getStackTrace() vor der Protokollanweisung aufzurufen. Dies machte keinen Unterschied.

Also entschied ich mich für einen Neustart mit aktiviertem Debug-Agent. Da ich jedoch selbst an den Prozess angeschlossen war, bemerkte ich, dass jetzt die Stack-Traces gedruckt wurden. Das Vorhandensein des Debug-Agenten führte also eindeutig dazu, dass einige zusätzliche Debug-Informationen verfügbar wurden.

Seitdem habe ich die Ursache der Ausnahme behoben. Aber ich würde gerne erfahren, warum der Stack-Trace ohne Debugger nicht verfügbar war. Weiß jemand?

Klärung: Dies ist kein Protokollierungsproblem. Stellen Sie sich die gleiche try/catch-Klausel vor, aber im catch drucke ich den Wert von:

e.getStackTrace().length

Ohne Debugger gibt dies ‘0’ aus, mit einem Debugger eine positive Zahl (in diesem Fall 9).

Weitere Informationen: Dies geschieht auf JDK 1.6.0_13, 64bit, AMD64, Linux 2.6.9

  • welche VM verwendest du? dieses Verhalten klingt sehr seltsam.

    – Michael Willes

    2. Juli 2009 um 19:47 Uhr

  • JDK 1.6.0_13, 64-Bit unter Linux 2.6.9

    – merkudat

    2. Juli 2009 um 19:54 Uhr

  • Was passiert, wenn Sie innerhalb des Versuchs selbst eine neue NullPointerException() werfen?

    – seth

    2. Juli 2009 um 20:07 Uhr

  • Versuchen Sie, die Aktionen zu protokollieren, damit Sie eine Vorstellung davon haben, welche Aktion dies verursacht

    – David Rabinowitz

    3. Juli 2009 um 8:53 Uhr

  • Das eigentliche Problem habe ich bereits behoben. Ich möchte nur eine Erklärung für dieses Verhalten.

    – merkudat

    3. Juli 2009 um 9:30 Uhr

Benutzer-Avatar
Vespa

Mit dem JVM-Flag -XX:-OmitStackTraceInFastThrow können Sie die Leistungsoptimierung der JVM für diesen Anwendungsfall deaktivieren. Wenn dieser Parameter angegeben wird, wodurch das Flag deaktiviert wird, ist der Stacktrace verfügbar.

Weitere Informationen finden Sie in den folgenden Versionshinweisen:

“Der Compiler in der Server-VM stellt jetzt korrekte Stack-Backtraces für alle “kalten” integrierten Ausnahmen bereit. Aus Leistungsgründen kann die Methode neu kompiliert werden, wenn eine solche Ausnahme einige Male ausgelöst wird. Nach der Neukompilierung kann der Compiler a schnellere Taktik mit vorab zugewiesenen Ausnahmen, die keinen Stack-Trace bereitstellen. Um die Verwendung von vorab zugewiesenen Ausnahmen vollständig zu deaktivieren, verwenden Sie dieses neue Flag: -XX:-OmitStackTraceInFastThrow.” http://java.sun.com/j2se/1.5.0/relnotes.html

  • Wir hatten das gleiche Problem erneut und haben diese Option ausprobiert, und es hat wirklich gut funktioniert, viel besser, als den JIT vollständig auszuschalten. Vielen Dank!

    – merkudat

    19. Januar 2010 um 12:21 Uhr

Benutzer-Avatar
Nick Fortescue

Ist es möglich, dass sich dieser Code in einer inneren Schleife befindet? Dann kompiliert der JIT-Compiler möglicherweise den Call-Stack dafür in nativen Code, wodurch die Stack-Informationen verloren gehen. Wenn Sie dann den Debugger anhängen, deaktiviert er JIT und macht die Informationen wieder verfügbar.

Die anderen manuellen Ausnahmen zeigen die Informationen weiterhin an, da der JIT nicht optimiert.

Es sieht so aus, als ob dies manchmal für andere aus einem Kommentar in diesem Klassenquellcode in Zeile 102 passieren kann:

http://logging.apache.org/log4j/1.2/xref/org/apache/log4j/spi/LocationInfo.html

  • Später konnte ich bestätigen, dass das Deaktivieren des JIT (JAVA_COMPILER=false) dazu führt, dass der vollständige Stack-Trace verfügbar ist, wenn diese Ausnahme auftritt.

    – merkudat

    13. Juli 2009 um 8:17 Uhr

Ich kann das replizieren, aber es scheint irgendwie seltsam, dass dies irgendwo in Ihrer Aktion passieren würde.

Wenn Sie setStackTrace mit einem leeren Array aufrufen, wird nur der Text angezeigt.

 public class Fark {
   public static void main(String[] args) {
       try {
           Fark.throwMe(args.length != 0);

       }
       catch (Exception e) {
           e.printStackTrace();
       }

   }

     public static final void throwMe(boolean arg) throws Exception{
         Exception e = new NullPointerException();
         if (arg) {
           e.setStackTrace(new StackTraceElement[0]);
         }
         throw e;
     }
 }

Laufen lassen….

% java Fark
java.lang.NullPointerException
        at Fark.throwMe(Fark.java:15)
        at Fark.main(Fark.java:5)

% java Fark nothing
java.lang.NullPointerException

  • Ja, das hat auch jemand erwähnt. Das ist nicht der Fall.

    – merkudat

    2. Juli 2009 um 20:54 Uhr

  • Passiert das Gleiche, wenn Sie beim Versuch einfach selbst eine NullPointerException werfen?

    – seth

    2. Juli 2009 um 21:24 Uhr

  • Ja, gleiches Verhalten, wenn ich selbst manuell werfe. Und das passiert nur in diesem try/catch. Bei anderen, bei denen ich manuell werfe, erhalte ich ein normales (dh volles Stack) Verhalten.

    – merkudat

    3. Juli 2009 um 7:12 Uhr

1054220cookie-checkNullPointerException-Stack-Trace ohne Debug-Agent nicht verfügbar

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy