Java異常日誌堆疊丟失的原因與排查
前言
查日誌是我們排查問題的重要手段之一,直接又方便。其中異常日誌堆疊資訊可以讓我們快速的發現問題所在,但稍微有點經驗的開發應該會遇到過日誌堆疊資訊丟失的情況。
堆疊只打印了一行:java.lang.NullPointerException,然後什麼資訊都沒有了,這是怎麼回事?
如果面試中,就可以提一些問題:
什麼情況下Java的異常日誌堆疊資訊會丟失?其原因是什麼? 異常堆疊丟失情況下要如何排查問題?
原因
JVM內部同一個方法被呼叫多次的時候,會被JIT編譯器進行優化,在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.
在Server模式下的JVM編譯器提供了一種方式可以讓我們回溯異常的堆疊資訊,但是出於效能的因素,當類似的異常丟擲多次的時候,異常方法可以被重新編譯,重新編譯後,編譯器會採用更快的策略使用預分配快取區的異常,並且不再提供堆疊資訊。
如果不想使用預分配快取的異常使用-XX:-OmitStackTraceInFastThrow標記。
另外一方面異常棧的獲取是非常消耗效能的,這點通過JVM內部預設會對一些異常不進行堆疊回溯也可以看出。
異常丟失如何排查
- 試著隔離一兩臺機器,重啟兩臺機器觀察情況
- -XX:-OmitStackTraceInFastThrow可以控制不進行異常堆疊優化,如果關閉,就需要預防產生“日誌風暴”,否則,一旦高頻應用出現異常可能很快用滿伺服器磁碟。
驗證堆疊丟失Demo
public class ExceptionLossDemo { public static void main(String[] args) { boolean flag = false; for (int i = 0;;i++){ boolean isExceptionStackLoss = exceptionTest(); if (isExceptionStackLoss) { flag = true; System.out.println("times:" + i + ",res:" + isExceptionStackLoss); } else if (flag) { System.out.println("times:" + i + ",res:" + isExceptionStackLoss); } } } public static boolean exceptionTest() { try { // 構造一個NPE異常 int res = ((Integer)null) + 1; } catch (Exception e) { if (e.getStackTrace().length == 0) { // 列印堆疊資訊 e.printStackTrace(); try { // 當出現 NPE 異常堆疊為空的時候,停留5秒,便於觀察 Thread.sleep(5000); } catch (Exception e1) { } // 如果出現 NPE 異常堆疊為空,返回true return true; } // 列印堆疊資訊 e.printStackTrace(); } return false; } }
最後
希望對大家有所幫助,技術不斷精進..
到此這篇關於Java異常日誌堆疊丟失的原因與排查的文章就介紹到這了,更多相關Java異常日誌堆疊丟失內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!