NullPointerException异常堆栈消失问题
程序中抛出了大量的NullPointerException,但是奇怪的是没有堆栈信息,明明是堆栈打印到日志中的。
后来发现在大量的NullPointerException日志中,有小部分是有堆栈信息的,大部分没有。原来是Hotspot JVM在1.5时添加了一项优化OmitStackTraceInFastThrow
。如果同一个异常被抛出很多次,则这个方法会被重新编译,重新编译后,这个方法会使用更快的抛出异常的方式,也就是一个预先分配好的不带堆栈信息的异常。所以在函数被JIT编译前,能看到堆栈信息,编译后,就没有堆栈信息了。
下面的代码可以模拟这种情况:
1 | public static void main(String[] args) { |
一开始会抛出正常的带堆栈信息的异常:
1 | java.lang.NullPointerException |
一段时间后就没有堆栈信息了:
1 | java.lang.NullPointerException |
这个优化可以通过参数-XX:-OmitStackTraceInFastThrow
关闭,这样就不会丢失堆栈了。
还有一个问题是什么异常会触发这个优化,所查资料没看到具体定义。大家举的例子都是NullPointerException。
我试着直接throw new NullPointerException()
是不会触发优化的,throw自定义异常也不会。
“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
从这段官方的原话中可以看出是针对“cold” built-in exceptions
,但是具体什么是“cold” built-in exceptions
还是不得而知。