在生产环境JRE 运行在server 模式下, 从日志上看大量的NullPointException日志打印时,没有堆栈信息输出。查了一下,JIT编译会对某些异常如果大量的抛出时,会进行优化,删除堆栈信息。
通过下面的代码可以重现问题
public class NullPointExceptionCountMain {
public static void main(String[] args) {
while (i <= 200000) {
try {
Long l = null;
l.toString();
} catch (Exception e) {
if (e.getStackTrace().length == 0) {
System.out.println("count is " + i);
break;
}
}
i++;
}
}
}
client 模式下运行,异常堆栈正常
java -classpath . NullPointExceptionCountMain
server 模式下运行,问题就重现出来。
java -server -classpath . NullPointExceptionCountMain
解决方案:
-
-XX:-OmitStackTraceInFastThrow 关闭异常堆栈优化
java -XX:-OmitStackTraceInFastThrow -classpath . NullPointExceptionCountMain
OmitStackTraceInFastThrow官方的说明
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.
-
-Xint 以解释模式执行
java -Xint -classpath . NullPointExceptionCountMain
注意的是,在解释模式 (interpreted mode) 下,-Xint 标记会强制 JVM 执行所有的字节码,当然这会降低运行速度,通常低 10 倍或更多。