JVM解惑:消失的异常堆栈,log中打印异常堆栈为空

最近在异常邮件(配置error级别日志发送邮件功能,详情见:https://blog.csdn.net/fz13768884254/article/details/81201407)中,查看相关异常信息时,并没有显示具体的异常堆栈信息:

正常邮件是这样的:

生产环境抛异常,但却没有将堆栈信息输出到日志,确认打印日志方法正确logger.error("somthing error", ex),发现这个日志捕捉了NullPointerException,但是没有异常堆栈信息,只有java.lang.NullPointerException这一条信息,无法知道是从哪里抛出来的, 经过分析是JIT编译器对异常进行了优化,当代码中的某个位置抛出同一个异常很多次后,JIT服务端编译器(C2)会将其优化成抛出一个事先编译好的、类型匹配的异常,异常堆栈信息就看不到了。官方解释:

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.

引用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。

解决方案:

         JVM提供了-XX:-OmitStackTraceInFastThrow这个虚拟机参数来告诉JIT编译器禁用这种异常fastThrow的优化,当然如果你使用-Xint参数后虚拟机运行在解释器模式也不会出现这个问题,但是禁用JIT会对整体的性能有影响,因此不建议使用-Xint参数,如果想看到具体的异常堆栈,推荐使用-XX:-OmitStackTraceInFastThrow参数。

猜你喜欢

转载自blog.csdn.net/fz13768884254/article/details/82222412