问题
系统上线时,查看问题日志时,有时候发现日志捕获了NullPointerException,但是缺没有任何的异常堆栈信息。只有一条信息:java.lang.NullPointerException
不清楚问题原因。
原因
HostSpot VM对异常进行了优化:fast throw。如果检测到代码中特定位置的异常抛出次数太多的话,就会决定用fast throw来对异常进行优化—直接抛出一个事先分配好的、类型匹配的异常对象。它的message和stack trace都是清空的。
引用R大的一段话: HotSpot VM有个许多人觉得“匪夷所思”的优化,叫做fast throw:有些特定的隐式异常类型(NullPointerException、ArithmeticException( / 0)之类)如果在代码里某个特定位置被抛出过多次的话,HotSpot Server Compiler(C2)会透明的决定用fast throw来优化这个抛出异常的地方——直接抛出一个事先分配好的、类型匹配的异常对象。这个对象的message和stack trace都被清空。抛出这个异常的速度是非常快,不但不用额外分配内存,而且也不用爬栈;但反面就是可能正好是需要知道哪里出问题的时候看不到stack trace了。从Sun JDK5开始要避免C2做这个优化还得额外传个VM参数:-XX:-OmitStackTraceInFastThrow。
复现
大量操作可以复现下。
public static void main(String[] args) {
for (int i = 0; i < 1000000; i++) {
try {
t();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void t(){
((Object)(null)).getClass();
}
运行一段时间后,出现如下:
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
解决
添加vm参数:-XX:-OmitStackTraceInFastThrow
即可解决。但是一般不建议添加,大量报错了,还是优先考虑去解决这个错误,而不是让它继续报错。