1. 程式人生 > >NullPointerException丟失異常堆疊資訊

NullPointerException丟失異常堆疊資訊

在生產環境上看到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之,stackoverflow答案。從別人的回答中,可以看到,這裡可能是jvm優化時,產生的結果。具體參考文章

這裡自己寫的程式碼,在接近執行兩萬次時,確實看到異常堆疊資訊就沒有了:

     
    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對這個功能有個開關,可以動態切換是否禁用此項優化。