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