jvm源码阅读笔记[6]-杂谈JIT中对Exception做的优化

在JVM的JIT编译中,特定异常如NullPointerException在优化后可能丢失堆栈信息。这一现象通常在-XX:+OmitStackTraceInFastThrow参数启用时发生,涉及的异常还包括ArithmeticException等。了解这一优化可以解释为何某些情况下异常日志缺乏详细堆栈。关闭此优化的参数为-XX:-OmitStackTraceInFastThrow。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    今天同事上线上看日志,发现一堆只打印了”java.lang.NullPointerException”的异常,代码里面确实捕获且调用了输出堆栈信息的方法,日志里面却没有堆栈信息,甚是困惑。另一个同事说他之前遇到过,好像是JIT优化的结果。搜了一下,找到这样一篇文章(http://jawspeak.com/2010/05/26/hotspot-caused-exceptions-to-lose-their-stack-traces-in-production-and-the-fix/)和代码:

public class NpeThief {
    public void callManyNPEInLoop() {
        for (int i = 0; i < 100000; i++) {
            try {
                ((Object)null).getClass();
            } catch (Exception e) {
                // This will switch from 2 to 0 (indicating our problem is happening)
                System.out.println(e.getStackTrace().length);
            }
        }
    }
    public static void main(String ... args) {
        NpeThief thief = new NpeThief();
        thief.callManyNPEInLoop();
    }
}

    
以下为启动参数时,在4W+次的时候就开始不打印堆栈信息了:
    

-Xcomp -server

    
    -Xcomp表示纯编译执行(-Xcomp):所有方法在第一次调用的时候就开始执行编译,会导致启动速度慢。
相对应的是分层编译(-XX:+TieredCompilation): 分别是client启动时的c1编译器和server启动时的c2编译器。这2个编译器的目标不同。c2编译需要大量的统计信息,且编译慢,但是编译完的代码执行效率高。C1编译需要的信息相对少,但是编译快,效率相对低。分层编译就是一个折中,在系统启动的初期,用c1编译以便尽快进入编译执行。然后随着时间执行,大量的统计信息之后,再利用C2编译,以达到性能最大化。

    在文章里面看到这样一个参数

-XX:-OmitStackTraceInFastThrow

    
    用该参数作为关键字搜了一下hotspot源码,发现以下这段关键代码:
    

 if (treat_throw_as_hot
      && (!StackTraceInThrowable || OmitStackTraceInFastThrow)) {
    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(默认值就是true),NullPointerException,ArithmeticException,ArrayIndexOutOfBoundsException,ArrayStoreException,ClassCastException这5种异常在经过JIT优化后都不会输出堆栈信息。主要是空指针异常,除0的异常,数组越界异常,数组存储异常和类型转换异常。
    感觉这种情况应该很少见,开启编译模式,都在调用了4W+后才发生。若只是分层编译,在10W+才出现。先记录一下。JIT这块也没有什么深入的理解。要关闭这个也很简单,-XX:-OmitStackTraceInFastThrow即可。
    最后附上R大的一篇回答链接
https://www.zhihu.com/question/21405047

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值