java.lang.NullPointerException: null 不显示异常栈

一、问题

排查线上问题时,发现日志中异常输出的地方,仅有一行java.lang.NullPointerException: null,截图如下。
在这里插入图片描述
丢失了具体的异常栈,导致无法定位是哪行代码抛出了异常。

这里排除日志用法的问题,以前是正常能输出异常栈的。

二、原因

HotSpot VM有个许多人觉得“匪夷所思”的优化,叫做fast throw:有些特定的隐式异常类型(NullPointerException、ArithmeticException( / 0)之类)如果在代码里某个特定位置被抛出过多次的话,HotSpot Server Compiler(C2)会透明的决定用fast throw来优化这个抛出异常的地方——直接抛出一个事先分配好的、类型匹配的异常对象这个对象的message和stack trace都被清空;抛出这个异常的速度就会非常快,不但不用额外分配内存,而且也不用爬栈。但反面就是可能正好是需要知道哪里出问题的时候看不到stack trace了。从Sun JDK5开始要避免C2做这个优化,需要用户额外传个VM参数:-XX:-OmitStackTraceInFastThrow在这里插入图片描述
出处:https://www.oracle.com/java/technologies/javase/release-notes-introduction.html#vm

java.lang.NullPointerException 报错115715次左右后,不再打印异常栈

java.lang.ArithmeticException 报错41984次左右后,不再打印异常栈

三、复现&解决

1. 复现

1.1 java.lang.ArithmeticException复现

public static void main(String[] args) {
    for(int i = 0; i < 300000; i++) {
        try {
            System.out.println(1/0);
        } catch (Exception e) {
            System.out.println("已报错" + i + "次!");
            if (e.getStackTrace().length == 0) {
                System.out.println("异常栈追踪停止,报错次数为:" + i);
                e.getStackTrace();
                break;
            }
        }
    }
}

循环报错30W次,ArithmeticException异常在报错41984次左右后,不再进行打印异常栈。
java.lang.NullPointerException: null 不显示异常栈_第1张图片

1.2 java.lang.NullPointerException 复现

这个异常不能直接使用idea运行复现,需要使用基础的Java命令执行才可以。
代码如下:

public static void main(String[] args) {
    for(int i = 0; i < 300000; i++) {
        try {
            ((Object)null).getClass();
        } catch (Exception e) {
            System.out.println("已报错" + i + "次!");
            if (e.getStackTrace().length == 0) {
                e.printStackTrace();
                System.out.println("异常栈追踪停止,报错次数为:" + i);
                break;
            }
        }
    }
}

运行

## 进入到classes文件根目录
cd ~/IdeaProjects/my_project/jtest/jdk/target/classes
## 执行classes类
java  com.kaka.jtest.jdk.jvm.other.FastThrow

循环报错30W次,NullPointerException异常在报错115715次左右后,不再进行打印异常栈。
java.lang.NullPointerException: null 不显示异常栈_第2张图片

2. 解决

使用idea运行前增加-XX:-OmitStackTraceInFastThrow参数即可。
java.lang.NullPointerException: null 不显示异常栈_第3张图片
ArithmeticException异常正常报错30W次,没有再被优化。
java.lang.NullPointerException: null 不显示异常栈_第4张图片

四、随便聊聊

其实这个问题比较难遇到,但当遇到时一定要知道其背后的原因。经验 = 踩过的坑 + 避坑办法,随着经验的不断累积,会潜移默化的影响你解决问题的思路。

第一次运行classes的姿势不对(直接在classes文件目录中,使用了Java命令),能快速调整正确,其实就是多年前曾踩过类似的坑。

运行classes文件

使用Java命令运行一个classes文件时,需要在该主类的全路径,对应根目录执行。因为Java以执行目录为基础,根据全类名去一层层的去找classes文件。

你可能感兴趣的:(jvm,java,开发语言)