欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

NullPointerException丢失异常堆栈信息

程序员文章站 2022-07-14 11:16:58
...
源:http://blog.csdn.net/taotao4/article/details/43918131
评:
在生产环境上看到tomcat/log/catalina.out一直输出异常信息,但是不见异常堆栈信息。
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException
java.lang.NullPointerException


在使用log4j中,调用异常方法exception.getStackTrace()获取到异常堆栈信息数组StackTraceElement[],然后使用方法log.error(String msg)来循环打印StackTraceElement。(这种做法是不是很诡异-_-)。没发现任何与异常相关的信息打印出来。


java的标准输出在tomcat启动时,被管道重定向到了catalina.out,catalina.out信息来自所有标准输出。我们在catalina.out看到了信息,说明异常出现时,调用了标准输出,但是没有任何异常堆栈信息出来;我们在log4j配置的文件中没有找到任何异常信息说明StackTraceElement[]中没有任何信息。

最开始怀疑是log4j的使用方式有问题,导致打印不出来,但是当前的使用方式只会丢失rootCause,不会丢弃所有的异常堆栈。catalina.out中就以为是使用了标准输出打印异常类名...。事实当然不是这样,后来查看了异常处理点,基本上都会调用printStackTrace(),然后调用log4j来输出异常到其他文件。说明异常的堆栈信息确实丢失了。

异常堆栈丢失了,然后google之,*答案。从别人的回答中,可以看到,这里可能是jvm优化时,产生的结果。具体参考文章
这里自己写的代码,在接近执行两万次时,确实看到异常堆栈信息就没有了:
[java] view plain copy
  
public static void main(String[] args) {  
    int i = 0; 
    String x= null; 
    while (i < 100000000) { 
        try { 
            System.out.println("当前执行次数为:"+i); 
            getNPE(x); 
        } catch (Exception e) { 
            int lth = e.getStackTrace().length; 
        System.out.println("length:"+lth); 
            e.printStackTrace(); 
            if(lth==0){ 
            return; 
        } 
        } 
        i++; 
    } 
     
 
}  
 
private static void getNPE(String x){ 
    System.out.println("当前字母为:"+x.toString()); 

测试时java版本信息:
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)
当增加虚拟机参数-XX:-OmitStackTraceInFastThrow后,执行了100w次以上,也不见异常堆栈信息丢失。
看看oracle的官方解释:
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.
这里的"cold",个人以为是与hotspot VM中hot相对的意思,意思是非热点内置异常。如果异常被抛出数次,就变成”hot“了,这时就会丢失异常信息,因为这时的异常是预先分配的。
在查找资料的时候,发现淘宝定制的vm对这个功能有个开关,可以动态切换是否禁用此项优化。
参考链接:http://www.oracle.com/technetwork/java/javase/relnotes-139183.html