1.可用率报警后查看异常日志,发现打印的异常信息,没有堆栈信息
2.检查日志打印格式,是按照异常对象打印的,是正确的打印方式,代码如下
try {
......
} catch (Throwable t){
LOGGER.error(ThreadLocalUtil.get() + "批量获取距离异常:", t);
......
} finally {
ThreadLocalUtil.clear();
}
3.继续查询相关资料,发现是jvm做的优化
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.
虚拟机打印堆栈超过一定次数以后,会关闭掉异常堆栈的打印,通过-XX:-OmitStackTraceInFastThrow 参数可禁用掉该优化
4.测试复现验证,代码如下
public class ExceptionTraceTest {
public static void main(String[] args) {
int i =0;
String test = null;
while (true){
try {
test.length();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
最开始的输出,异常信息中有堆栈信息
java.lang.NullPointerException
at com.shuaisam.reboot.jvm.param.ExceptionTraceTest.main(ExceptionTraceTest.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
java.lang.NullPointerException
at com.shuaisam.reboot.jvm.param.ExceptionTraceTest.main(ExceptionTraceTest.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
输出一定数量以后,异常信息中只有异常message信息,没有了堆栈
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
5.加入jvm参数 -XX:-OmitStackTraceInFastThrow 重新运行代码
继续运行,一段时间后异常仍然全部打印出了堆栈,现象符合预期
6.解决办法
- 历史日志还在的话,查看历史日志异常堆栈
- 重新启动服务器,再观察日志
- 设置JVM参数,暂时禁止掉这个优化选项: -XX:-OmitStackTraceInFastThrow
7.参考资料
https://stackoverflow.com/questions/2295015/log4j-not-printing-the-stacktrace-for-exceptions
网友评论