没有调试代理程序,NullPointerException堆栈跟踪不可用

ome*_*dat 58 java logging nullpointerexception stack-trace

我最近发现了一个导致NullPointerException的错误.使用标准的slf4j语句捕获并记录异常.以下简要代码:

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

正如你所看到的,没什么特别的.但是,在我们拥有的所有异常日志记录语句中,只有这一个不打印堆栈跟踪.它打印的全部是消息(表示为"...")和异常类的名称(java.lang.NullPointerException).

由于异常上的堆栈跟踪是延迟加载的,我想可能存在某种指令重新排序问题,并决定在日志语句之前调用e.getStackTrace().这没有任何区别.

所以我决定在启用调试代理的情况下重新启动.但是,因为我甚至连接到这个过程,我注意到现在堆栈的痕迹正在打印.很明显,调试代理的存在导致一些额外的调试信息变得可用.

从那时起我就修复了异常的根本原因.但我想了解为什么没有调试器就无法使用堆栈跟踪.谁知道?

澄清:这不是日志记录问题.想象一下相同的try/catch子句,但在catch中,我打印的值为:

e.getStackTrace().length
Run Code Online (Sandbox Code Playgroud)

没有调试器,它打印'0',调试器打印一个正数(在这种情况下为9).

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

小智 89

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

有关更多信息,请查看以下发行说明:

"服务器VM中的编译器现在为所有"冷"内置异常提供正确的堆栈回溯.出于性能目的,当抛出这样的异常几次时,可以重新编译该方法.重新编译后,编译器可以选择使用未提供堆栈跟踪的预分配异常的更快策略.要完全禁用预分配异常,请使用以下新标志:-XX:-OmitStackTraceInFastThrow." http://java.sun.com/j2se/1.5.0/relnotes.html

  • 我们再次遇到了同样的问题并尝试了这个选项,它运行得非常好,比完全关闭JIT要好得多.谢谢! (3认同)

Nic*_*cue 19

这段代码是否可能在内循环中?然后,JIT编译器可能正在将此调用堆栈编译为本机代码,从而丢失堆栈信息.然后,当您附加调试器时,它会禁用JIT,使信息再次可用.

其他手动异常会在JIT未优化时继续显示信息.

在第102行的这个类源代码中的注释中,有时会发生这种情况:

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

  • 后来我设法确认关闭JIT(JAVA_COMPILER = false)会导致完整的堆栈跟踪在发生此异常时可用. (3认同)