今天去服務器后台看日志,發現有很多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后,異常就能正常輸出。
