59

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

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

如您所见,没有什么特别的。但是,在我们拥有的所有异常日志语句中,只有这一条不会打印堆栈跟踪。它只打印消息(表示为“...”)和异常类的名称(java.lang.NullPointerException)。

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

所以我决定在启用调试代理的情况下重新启动。但是,因为我什至附加到进程,我注意到现在堆栈跟踪正在打印。很明显,调试代理的存在导致一些额外的调试信息变得可用。

从那以后,我已经修复了异常的根本原因。但是我想了解为什么没有调试器就无法使用堆栈跟踪。有人知道吗?

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

e.getStackTrace().length

如果没有调试器,它会打印“0”,使用调试器会打印一个正数(在这种情况下为 9)。

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

4

3 回答 3

90

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

For more information please have a look at the following release notes:

"The compiler in the server VM now provides correct stack backtraces for all "cold" built-in exceptions. For performance purposes, when such an exception is thrown a few times, the method may be recompiled. After recompilation, the compiler may choose a faster tactic using preallocated exceptions that do not provide a stack trace. To disable completely the use of preallocated exceptions, use this new flag: -XX:-OmitStackTraceInFastThrow." http://java.sun.com/j2se/1.5.0/relnotes.html

于 2010-01-15T09:35:07.263 回答
20

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

由于 JIT 未优化,其他手动异常会继续显示信息。

从第 102 行的此类源代码中的注释中,其他人似乎有时会发生这种情况:

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

于 2009-07-03T15:18:08.497 回答
0

我可以复制这个,但是这似乎有点奇怪,这会发生在你的 Action 某处。

如果您使用空数组调用 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
于 2009-07-02T20:21:22.687 回答