查看線上日志,遇到一個詭異的問題,就是系統大量空指針的異常,但是沒有打印堆棧,導致不方便定位問題。
經過一番代碼調試,確定並非程序代碼問題。沒有線索之后,從Google找到了答案:是因為在server模式下運行的時候,有一個默認選項是-XX:+OmitStackTraceInFastThrow,這個玩意的意思就是當大量拋出同樣的異常的后,后面的異常輸出將不打印堆棧,打印堆棧的時候底層會調用到Throwable.getOurStackTrace()方法,而這個方法是synchronized的,對性能有比較明顯對影響。所以這個參數是合理的。正常情況下,如果打印了幾萬條異常堆棧是很容易發現問題的。但是我們的系統正好趕上訪問量高峰,一不留神就錯過打印詳細堆棧的階段了。
復現測試代碼:
public class NullPointExceptionTest {
static final Logger logger = LoggerFactory.getLogger(NullPointExceptionTest.class);
public static void main(String[] args) {
String test = null;
int i = 0;
while (true) {
try {
test.length();
} catch (Exception e) {
System.out.println(i++ + " - " + e.getStackTrace().length);
if (e.getStackTrace().length == 0) {
logger.error("e is", e);
break;
}
}
}
}
}
知道原因后,那我們的解決辦法可以有:
- 歷史數據還在的話,下載歷史數據查看;
- 重新啟動服務器,再觀察日志;
- 設置JVM參數,暫時禁止掉這個優化選項:-XX:+OmitStackTraceInFastThrow。
