今天去服務器后台看日志,發現有很多NullPointerException異常。我下意識的去找異常棧信息,想看下到底是哪行代碼導致了空指針。但是發現日志中只打印出了如下日志:
null
java.lang.NullPointerException: null
我懷疑是不是打印日志的時候沒有將異常棧打印出來,於是又去翻看應用代碼核實。但是發現日志打印的代碼也是正常的。
logger.error(e.getMessage(),e);
這就納悶了,於是又懷疑是不是日志配置有問題。折騰了一番發現這些配置都沒問題。一時沒有了思路,只好去求助萬能的百度。
問題原因
我在網上找到了這么一段描述:
JVM 虛擬機會對異常信息進行優化,當相同異常出現很多次,會認為它是熱點異常,忽略掉異常堆棧信息;通過增加 JVM 參數:-XX:-OmitStackTraceInFastThrow 可解決。
這個描述能很好的解釋我發現的問題。代碼中出現空指針異常的地方是一個定時任務在不停地調用,當這個異常出現次數太多時 JVM 就會將其過濾掉。
為了驗證我的猜想,我去找了下這個服務剛剛啟動時的代碼,發現這個異常棧是正常打出的,這也驗證了自己的猜想,通過異常棧信息也找到了導致空指針異常的代碼。
問題重現
下面是自己寫的一段代碼來顯示這個額問題:
public class NullPointStackMissBug {
static Logger logger = LoggerFactory.getLogger(NullPointStackMissBug.class);
public static void main(String[] args) {
for (int i = 0; i < 100000 ; i++) {
try{
System.out.println("Loop:"+(i+1));
String str = "test";
if(true){
str = null;
}
str.toUpperCase();
}catch (Exception e){
logger.error(e.getMessage(),e);
}
}
}
}
在JVM啟動參數中增加:-XX:-OmitStackTraceInFastThrow后,異常就能正常輸出。
