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

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

然后错误日志是这样的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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

https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dec5a6f940924d6ca465f616f6d43be9~tplv-k3u1fbpfcp-watermark.image

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

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

开个玩笑。。。


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

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

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

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

下面是官方给出的解释:

https://www.oracle.com/java/technologies/javase/release-notes-introduction.html#vm

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

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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、翻线上日志,找到有完整堆栈信息的日志。

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

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

https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/86aa30985b4a4d859b606272a663ac53~tplv-k3u1fbpfcp-watermark.image