没有debugging代理,NullPointerException堆栈跟踪不可用

我最近发现了一个导致NullPointerException的bug。 使用标准的slf4j语句捕获并loggingexception。 以下摘录代码:

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

正如你所看到的,没有什么幻想。 但是,在我们所有的exception日志语句中,只有这个不打印堆栈跟踪。 所有它打印的是消息(表示为“…”)和exception类的名称(java.lang.NullPointerException)。

由于exception的堆栈跟踪是懒加载的,我想也许有一种指令重新sorting的问题,并决定在日志语句之前调用e.getStackTrace()。 这没有什么区别。

所以我决定重新启动debugging代理。 但是,因为我甚至连接到进程,我注意到现在堆栈跟踪正在打印。 所以很显然,debugging代理的存在会导致一些额外的debugging信息变得可用。

我从那以后解决了exception的根本原因。 但我想知道为什么没有debugging器的堆栈跟踪是不可用的。 有人知道吗?

澄清: 这不是一个日志logging问题 。 想象一下同样的try / catch子句,但在catch中,我打印出下面的值:

 e.getStackTrace().length 

没有debugging器打印“0”,用debugging器打印一个正数(在这种情况下是9)。

更多信息:这发生在JDK 1.6.0_13,64位,amd64,linux 2.6.9上

这段代码是否可能在内部循环中? 然后,JIT编译器可能会编译调用堆栈,以将其转换为本地代码,从而丢失堆栈信息。 然后,当您连接debugging器时,将禁用JIT,使信息再次可用。

由于JIT没有优化,其他手动exception会显示信息。

它看起来像有时可能会发生在这个类源代码在102行的评论:

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

使用JVM标志-XX:-OmitStackTraceInFastThrow,您可以禁用此用例的JVM性能优化。 如果给出这个参数,禁用该标志,堆栈跟踪将可用。

有关更多信息,请参阅以下发行说明:

“现在,服务器虚拟机中的编译器为所有”冷“内置exception提供了正确的堆栈回溯,出于性能的考虑,当这样的exception抛出几次时,可能会重新编译该方法,重新编译之后,编译器可以select更快的策略,使用预先分配的不提供堆栈跟踪的exception。要完全禁用预分配的exception,请使用以下新标志:-XX:-OmitStackTraceInFastThrow。 http://java.sun.com/j2se/1.5.0/relnotes.html

我可以复制这个,但似乎有点奇怪,这将发生在你的行动某处。

如果用空数组调用setStackTrace,则只会显示文本。

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

运行它….

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