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[],然後
java的標準輸出在tomcat啟動時,被管道重定向到了catalina.out,catalina.out資訊來自所有標準輸出。我們在catalina.out看到了資訊,說明異常出現時,呼叫了標準輸出,但是沒有任何異常堆疊資訊出來;我們在log4j配置的檔案中沒有找到任何異常資訊說明StackTraceElement[]中沒有任何資訊。
最開始懷疑是log4j的使用方式有問題,導致打印不出來,但是當前的使用方式只會丟失rootCause,不會丟棄所有的異常堆疊。catalina.out中就以為是使用了標準輸出列印異常類名...。事實當然不是這樣,後來查看了異常處理點,基本上都會呼叫
異常堆疊丟失了,然後google之,stackoverflow答案。從別人的回答中,可以看到,這裡可能是jvm優化時,產生的結果。具體參考文章
這裡自己寫的程式碼,在接近執行兩萬次時,確實看到異常堆疊資訊就沒有了:
測試時java版本資訊: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 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對這個功能有個開關,可以動態切換是否禁用此項優化。