JVM 抛出异常,堆栈信息竟离奇消失

733 阅读2分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

事情是这样的,开开心心的在开发环境跑着定时任务,就上个厕所的功夫,回来就发现报错了。

然后错误日志是这样的:

Exception in thread "pool-1-thread-40699" java.lang.NullPointerException
Exception in thread "pool-1-thread-40681" java.lang.NullPointerException
Exception in thread "pool-1-thread-40704" java.lang.NullPointerException
Exception in thread "pool-1-thread-40688" java.lang.NullPointerException
Exception in thread "pool-1-thread-40691" java.lang.NullPointerException
Exception in thread "pool-1-thread-40692" java.lang.NullPointerException
Exception in thread "pool-1-thread-40719" java.lang.NullPointerException
Exception in thread "pool-1-thread-40713" java.lang.NullPointerException
Exception in thread "pool-1-thread-40715" java.lang.NullPointerException
Exception in thread "pool-1-thread-40722" java.lang.NullPointerException

image.png

我的堆栈信息呢?虽然平时最不想看到的就是报错,但是这次只有这么点是几个意思?

当然这难不倒我,只要我足够细心,仔仔细细的排查一下这个2000多行的类文件,就可以发现问题!

开个玩笑。。。


实际上,这是JVM的一个优化,当某处代码高频率的抛出同一异常时,为了节约性能,JVM不会再打印完整异常堆栈信息。

这个优化是默认开启的,当然也可以关闭。

只需要在启动时,加上如下参数即可:

-XX:-OmitStackTraceInFastThrow //(减号表示关闭,加号则表示启用)

下面是官方给出的解释:

www.oracle.com/java/techno…

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

下面给出伪代码复现一下:

public static void main(String[] args) {

    ExecutorService threadPool = Executors.newFixedThreadPool(10);

    for (int j = 0; j < 200000; j++) {
        threadPool.execute(() -> {
            String str = null;
            str.toString();
        });
    }
}

执行之后,完整的堆栈信息很快就不会打印了。

这个情况是发生在开发环境,如果是在线上环境,我这边有两个解决思路:

1、在开发环境复现

2、翻线上日志,找到有完整堆栈信息的日志。

如非必要,不要在生产环境关闭这个优化。

好了,今天就到这里,我们下期再见~

0190747A.png