在日志中排查NullPointerException的时候,发现没有打印异常堆栈。log.error的写法也没问题,最后发现是Java的一个Fast Throw特性。
JVM只对几个特定类型异常开启了Fast Throw优化,这些异常包括:
- NullPointerException
- ArithmeticException
- ArrayIndexOutOfBoundsException
- ArrayStoreException
- ClassCastException
这是HotSpot VM专门针对异常做的一个优化,称为fast throw,当一些异常在代码里某个特定位置被抛出很多次的话,HotSpot Server Compiler(C2)会用fast throw来优化这个抛出异常的地方,直接抛出一个事先分配好的、类型匹配的对象,这个对象的message和stack trace都被清空。
这个优化的目的是,抛出这个异常非常快,不用额外分配内存,也不用爬栈。但是问题是找异常stack trace需要翻到最前面几次抛异常的地方,排查问题的时候需要注意。
通过 -XX:-OmitStackTraceInFastThrow 禁用该默认的优化。