首页 > 其他 > 详细

强制要求JVM始终抛出含堆栈的异常(-XX:-OmitStackTraceInFastThrow)

时间:2020-02-17 21:11:16      阅读:87      评论:0      收藏:0      [点我收藏+]

线上环境异常没有打印栈信息解决思路:

问题描述:

生产环境抛异常,log.error("这里发生错误", e),但却没有将堆栈信息输出到日志文件(在本地调试是有的,无法复现),导致定位问题无法准确定位到代码行。

问题分析:

它跟JDK5的一个新特性有关,即jvm启动参数-XX:-OmitStackTraceInFastThrow,参数:OmitStackTraceInFastThrow字面意思是省略异常栈信息从而快速抛出。对于一些频繁抛出的异常,JDK为了性能会做一个优化,即JIT重新编译后会抛出没有堆栈的异常,而在使用-server模式时,该优化选项是开启的,因此在频繁抛出某个异常一段时间后,该优化开始起作用,即只抛出没有堆栈的异常信息。
相关源码:
  // If this throw happens frequently, an uncommon trap might cause
  // a performance pothole.  If there is a local exception handler,
  // and if this particular bytecode appears to be deoptimizing often,
  // let us handle the throw inline, with a preconstructed instance.
  // Note:   If the deopt count has blown up, the uncommon trap
  // runtime is going to flush this nmethod, not matter what.
  // 这里要满足两个条件:1.检测到频繁抛出异常,2. OmitStackTraceInFastThrow为true,或StackTraceInThrowable为false
  if (treat_throw_as_hot
      && (!StackTraceInThrowable || OmitStackTraceInFastThrow)) {
    // If the throw is local, we use a pre-existing instance and
    // punt on the backtrace.  This would lead to a missing backtrace
    // (a repeat of 4292742) if the backtrace object is ever asked
    // for its backtrace.
    // Fixing this remaining case of 4292742 requires some flavor of
    // escape analysis.  Leave that for the future.
    ciInstance* ex_obj = NULL;
    switch (reason) {
    case Deoptimization::Reason_null_check:
      ex_obj = env()->NullPointerException_instance();
      break;
    case Deoptimization::Reason_div0_check:
      ex_obj = env()->ArithmeticException_instance();
      break;
    case Deoptimization::Reason_range_check:
      ex_obj = env()->ArrayIndexOutOfBoundsException_instance();
      break;
    case Deoptimization::Reason_class_check:
      if (java_bc() == Bytecodes::_aastore) {
        ex_obj = env()->ArrayStoreException_instance();
      } else {
        ex_obj = env()->ClassCastException_instance();
      }
      break;
    }
    ... ...
}

OmitStackTraceInFastThrow和StackTraceInThrowable都默认为true。所以条件 (!StackTraceInThrowable || OmitStackTraceInFastThrow)为true,即JVM默认开启了Fast Throw优化。通过实测发现在若干次(测试多次,发现每次次数不一样,有可能是JVM内部是一个动态值)以后便不打印堆栈信息。

测试代码如下:

 public static void main(String[] args)
    {
        String test = null;
        int i = 0;
        while (true)
        {
            try
            {
                test.length();
            }
            catch (Exception e)
            {
                System.out.println("次数为:" + i++ + ",堆栈长度为:" + e.getStackTrace().length);
                //log.error("StackTrace is ",e);
                if (e.getStackTrace().length == 0)
                {
                    log.error("no StackTrace is ", e);
                    break;
                }
            }
        }
    }

问题解决:

方法一:由于该优化是在JIT重新编译后才起作用,因此起初抛出的异常还是有堆栈的,所以可以查看较旧的日志,寻找完整的堆栈信息
方法二:另一个解决办法是禁用该优化,即强制要求每次都要抛出有堆栈的异常, 即-XX:-OmitStackTraceInFastThrow,便可禁用该优化了(注意选项中的减号,加号则表示启用)

1)在idea中添加启动参数,如下图:

技术分享图片

 2)在生产环境中添加启动参数,如:

local OMIT_STACKTRACE_OPTS="-XX:-OmitStackTraceInFastThrow"
nohup $JAVA_HOME/bin/java $OMIT_STACKTRACE_OPTS -jar $JAR_NAME >/dev/null 2>&1 &

注:

JVM只对几个特定类型异常开启了Fast Throw优化,这些异常包括:

NullPointerException
ArithmeticException
ArrayIndexOutOfBoundsException
ArrayStoreException
ClassCastException

强制要求JVM始终抛出含堆栈的异常(-XX:-OmitStackTraceInFastThrow)

原文:https://www.cnblogs.com/share-duke/p/12323576.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!