jvm原始碼閱讀筆記[6]-雜談JIT中對Exception做的優化
public class NpeThief {
public void callManyNPEInLoop() {
for (int i = 0; i < 100000; i++) {
try {
((Object)null).getClass();
} catch (Exception e) {
// This will switch from 2 to 0 (indicating our problem is happening)
System.out.println(e.getStackTrace().length);
}
}
}
public static void main(String ... args) {
NpeThief thief = new NpeThief();
thief.callManyNPEInLoop();
}
}
以下為啟動引數時,在4W+次的時候就開始不列印堆疊資訊了:
-Xcomp -server
-Xcomp表示純編譯執行(-Xcomp):所有方法在第一次呼叫的時候就開始執行編譯,會導致啟動速度慢。
相對應的是分層編譯(-XX:+TieredCompilation): 分別是client啟動時的c1編譯器和server啟動時的c2編譯器。這2個編譯器的目標不同。c2編譯需要大量的統計資訊,且編譯慢,但是編譯完的程式碼執行效率高。C1編譯需要的資訊相對少,但是編譯快,效率相對低。分層編譯就是一個折中,在系統啟動的初期,用c1編譯以便儘快進入編譯執行。然後隨著時間執行,大量的統計資訊之後,再利用C2編譯,以達到效能最大化。
在文章裡面看到這樣一個引數
-XX:-OmitStackTraceInFastThrow
用該引數作為關鍵字搜了一下hotspot原始碼,發現以下這段關鍵程式碼:
if (treat_throw_as_hot
&& (!StackTraceInThrowable || OmitStackTraceInFastThrow)) {
ciInstance* ex_obj = NULL;
switch (reason) {
case Deoptimization::Reason_null_check:
ex_obj = env()->NullPointerException_instance();
break ;
case Deoptimization::Reason_div0_check:
ex_obj = env()->ArithmeticException_instance();
break;
case Deoptimization::Reason_range_check:
ex_obj = env()->ArrayIndexOutOfBoundsException_instance();
break;
case Deoptimization::Reason_class_check:
if (java_bc() == Bytecodes::_aastore) {
ex_obj = env()->ArrayStoreException_instance();
} else {
ex_obj = env()->ClassCastException_instance();
}
break;
}
可以看到,當開啟引數OmitStackTraceInFastThrow(預設值就是true),NullPointerException,ArithmeticException,ArrayIndexOutOfBoundsException,ArrayStoreException,ClassCastException這5種異常在經過JIT優化後都不會輸出堆疊資訊。主要是空指標異常,除0的異常,陣列越界異常,陣列儲存異常和型別轉換異常。
感覺這種情況應該很少見,開啟編譯模式,都在呼叫了4W+後才發生。若只是分層編譯,在10W+才出現。先記錄一下。JIT這塊也沒有什麼深入的理解。要關閉這個也很簡單,-XX:-OmitStackTraceInFastThrow即可。
最後附上R大的一篇回答連結
https://www.zhihu.com/question/21405047