如果没有调试代理,NullPointerException 堆栈跟踪将不可用
我最近发现了一个导致 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 上
I have recently found a bug that causes a NullPointerException. The exception is caught and logged using a standard slf4j statement. Abridged code below:
for(Action action : actions.getActions()) {
try {
context = action.execute(context);
} catch (Exception e) {
logger.error("...", e);
break;
}
}
As you can see, nothing fancy. However, of all the exception logging statements that we have, just this one does not print a stack trace. All it prints is the message (represented as "...") and the name of the exception class (java.lang.NullPointerException).
Since the stack trace on an exception is lazy loaded, I thought maybe there is a instruction reordering issue of some sort and decided to call e.getStackTrace() before the log statement. This made no difference.
So I decided to restart with the debug agent enabled. However, because I even attached to the process, I noticed that now the stack traces were printing. So clearly the presence of the debug agent caused some additional debug information to become available.
I have since then fixed the root cause of the exception. But I would like to learn why the stack trace was unavailable without a debugger. Anyone know?
Clarification: this is not a logging issue. Imagine the same try/catch clause, but in the catch, I print the value of:
e.getStackTrace().length
Without a debugger this prints '0', with a debugger it prints a positive number (9 in this case).
More info: this is happening on JDK 1.6.0_13, 64bit, amd64, linux 2.6.9
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 JVM 标志 -XX:-OmitStackTraceInFastThrow,您可以针对此用例禁用 JVM 的性能优化。 如果给出此参数,则禁用该标志,堆栈跟踪将可用。
有关更多信息,请查看以下发行说明:
“服务器 VM 中的编译器现在为所有“冷”内置异常提供正确的堆栈回溯。出于性能目的,当多次抛出此类异常时,重新编译后,编译器可能会选择使用不提供堆栈跟踪的预分配异常的更快策略。要完全禁用预分配异常,请使用此新标志:-XX:-OmitStackTraceInFastThrow。 http://java.sun.com/j2se/1.5.0/relnotes.html
With the JVM flag -XX:-OmitStackTraceInFastThrow you can disable the performance optimization of the JVM for this use case. IF this parameter is given, which disables the flag, the stacktrace will be available.
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
这段代码有可能是在内循环中吗? 然后,JIT 编译器可能会将其调用堆栈编译为本机代码,从而丢失堆栈信息。 然后,当您连接调试器时,它会禁用 JIT,从而使信息再次可用。
由于 JIT 未优化,其他手动异常继续显示信息。
从此类源代码第 102 行的注释来看,其他人有时也会发生这种情况:
http://logging.apache.org/log4j/1.2/xref/org/apache/log4j/spi/LocationInfo.html
Is it possible that this code is in an inner loop? Then then JIT compiler might be compiling the call stack for this to native code, losing the stack information. Then when you attach the debugger it disables the JIT, making the information available again.
The other manual exceptions keep displaying the information as the JIT is not optimising.
It looks like this can sometimes happen for others from a comment in this class source code at line 102:
http://logging.apache.org/log4j/1.2/xref/org/apache/log4j/spi/LocationInfo.html
我可以复制这个,但是这似乎有点奇怪,这会发生在你的操作中的某个地方。
如果您使用空数组调用 setStackTrace,则会导致仅显示文本。
运行它....
I can replicate this but it seems kind of weird that this would be happening in your Action somewhere.
If you call setStackTrace with an empty array, that'll cause only the text to be shown.
Running it....