這是經過實驗的方式獲得的結論.由於沒有大大能夠進行明確指導,因此我以最終運行的結果爲準.歡迎指正.java
@Test public void test10() { int a, b, temp, count = 100000000; long start, time; Random random = new Random(); while (true) { System.out.println("-----------------------------------------------"); a = random.nextInt(); b = random.nextInt(); // 模運算部分 start = System.currentTimeMillis(); for (int i = 0; i < count; i++) { temp = a % b; preventOptimization(temp); } long modulo = System.currentTimeMillis() - start; // 與運算部分 start = System.currentTimeMillis(); for (int i = 0; i < count; i++) { temp = a & b; preventOptimization(temp); } long and = System.currentTimeMillis() - start; // 計算兩種運算的比 BigDecimal bigDecimal = new BigDecimal(and) .divide(new BigDecimal(modulo), 6, ROUND_DOWN); System.out.println(String.format("modulo: %sms, and: %sms, scale: %s", modulo, and, bigDecimal)); } } // private static int preventOptimizationVar = 0; // A /** * 用於阻止jvm的字節碼優化技術生效,優化掉for循環中的代碼<br> * * @param num */ private static void preventOptimization(int num) { // preventOptimizationVar += num; // A }
啓動時,須要添加JVM參數-Djava.compiler=NONE
阻止虛擬機的JIT優化ubuntu
preventOptimization
的做用原本是爲了防止for循環內的運算單元被優化.從結果看,沒法抵禦JIT優化,實際上只阻止了字節碼優化.preventOptimization
.內部添加了一個對成員變量preventOptimizationVar
的操做,本意一樣是是爲了阻止JIT優化,但效果出現誤差.-Djava.compiler=NONE
阻止JIT優化,同時調用空方法preventOptimization
阻止字節碼優化preventOptimization
方法,preventOptimizationVar
操做與-Djava.compiler=NONE
參數之間的交叉測試--------------------------- | -Djava.compiler=NONE | 不使用-Djava.compiler=NONE |
---|---|---|
preventOptimization(空方法) | 目標結果 | 只能執行第一次while ,以後除數爲0拋出異常.應該是for 循環被優化掉了 |
preventOptimization | 執行變得極慢且比值隨機位於1兩側.多是由於操做成員變量的時間已經把模與與運算的時間稀釋了 | 兩種運算的for 的平均用時只有個位數的毫秒數.通常爲4ms或5ms.能夠判定發生了JIT優化.可是這又與徹底跳過for 循環的行爲不一樣.中間產生了數毫秒的操做時間. |
不調用preventOptimization | 目標結果 | 只能執行第一次while ,以後除數爲0拋出異常.應該是for 循環被優化掉了 |
注: 上面的測試結果基於intel平臺上的ubuntu18.4操做系統.後面我會補上AMD平臺上的Windows系統的執行表格.它們之間會有輕微的不一樣dom
-Djava.compiler=NONE
,明確的禁用了JIT優化對於目前的這種狀況.要想徹底弄清誰快誰慢,其實能夠用一個最簡單也最直觀的方法進行確認.那就是去翻JDK源碼.先在字節碼裏找到負責與運算與模運算的指令,而後去找這個指令的JDK實現jvm
irem
.將操做數棧的兩個值進行餘運算(注意,這裏用的是餘運算.它不一樣於模運算)iand
.將操做數棧的兩個值進行與運算不要和我說什麼幾個階段,每一個階段都幹什麼.這多是個大坑.因此我得翻書(鴿了)啊ide