问题描述
近期查看测试环境日志,经常会打印一些没有堆栈的异常信息,对问题排查无疑是致命的。
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
第一反应是"什么鬼?",难得是日志组件出BUG了。后面才得知jvm针对频繁出现的异常做了优化,可以在出现异常的时候快速抛出,不需要打印出整个调用链,这样可以节省异常堆栈的内存分配。既然jvm针对这个做了优化,那肯定有禁用这个优化的方法,那就是-XX:-OmitStackTraceInFastThrow参数(禁用快抛,即展示完整异常),如果使用-XX:+OmitStackTraceInFastThrow则代表启用快抛,即会存在一些没有完整堆栈的异常。
测试
不加jvm参数,默认是启用快抛
public class WithNPE extends Thread {
private static int count = 0;
@Override
public void run() {
try{
System.out.println(this.getClass().getSimpleName()+"--"+(++count));
String str = null;
// 制造空指针NPE
System.out.println(str.length());
}catch (Throwable e){
e.printStackTrace();
}
}
}
public class FastThrowMain {
public static void main(String[] args) throws InterruptedException {
WithNPE withNPE = new WithNPE();
ExecutorService executorService = Executors.newFixedThreadPool(20);
for (int i=0; i<Integer.MAX_VALUE; i++) {
executorService.execute(withNPE);
Thread.sleep(2);
}
}
}
输出:
java.lang.NullPointerException
at com.xx.xx.mpp.WithNPE.run(WithNPE.java:18)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
增加-XX:-OmitStackTraceInFastThrow参数:
禁用快抛,全是完整异常:
java.lang.NullPointerException
at com.xx.xx.mpp.WithNPE.run(WithNPE.java:18)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
java.lang.NullPointerException
at com.xx.xx.mpp.WithNPE.run(WithNPE.java:18)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
总结
主要是了解jvm针对异常机制有这个优化,然后针对某些错误场景很难排查问题时可以禁用这个优化。如果日志保存的时间比较长,可以往上找,因为jvm的异常机制只是针对频率比较高的情况做了优化,肯定会存在一些完整堆栈的异常的。
网友评论