2011-07-03 50 views
2

我讀過一些JVM可以通過刪除邊界檢查來優化代碼執行。我想弄清楚的是編碼技術會更好地工作。Java邊界檢查優化示例

在方法下面例1將在JVM以往數字出來,並消除邊界的源[指數]參考的檢查?

example2更好的代碼練習?這似乎是這樣,但在循環內的一些算法中,索引超出範圍是正常情況。所以你不想在這個循環中產生大量的Exception對象。

public void example1(int [] source, int index) { 
    if (index >= 0 && index < source.length) 
     System.out.println("Value is " + source[index]); 
    else 
     System.out.println("Out of range: " + index); 
} 

public void example2(int [] source, int index) { 
    try {   
     System.out.println("Value is " + source[index]);   
    } catch (IndexOutOfBoundsException exp) { 
     System.out.println("Out of range: " + index); 
    } 
} 

這些代碼段只是代表性的。我知道在這些例子中,邊界檢查對於性能而言並不重要。不過,我正在研究嵌入式協議應用程序,其中冗餘邊界檢查將會加起來。

+0

[This](http://www.ssw.uni-linz.ac.at/Research/Papers/Wuerthinger07/Wuerthinger07.pdf)這裏的一些同事的論文應該對你很有意思。我認爲這些變化已被納入熱點,但不確定。無論如何,從性能和編碼實踐的角度來看,第二個例子肯定更糟糕。 – Voo

+0

@AlanObject,邊界檢查是多個數量級,比調用輸出要小。在大多數情況下,它沒有任何區別。 –

回答

5

對於你的第一個問題,在example1中邊界檢查可以從理論上被淘汰。我期望最好的現代JIT編譯器來做到這一點(例如,可能通過在擴展source [index]時在邊界檢查中通用的子表達式消除)。像往常一樣,這將取決於實施,所以你不能依賴它。 OTOH即使邊界檢查沒有被消除,差異將變得微不足道 - 你正在爲已經緩存的source.length內存位置進行操作,並進行了幾次整數比較,所以開銷很小。

example2不是很好的做法 - 你打了一個例外,但隨後捕捉它並繼續,就好像什麼都沒有發生。除非你仔細觀察標準輸出,否則你可能會完全錯過代碼中存在錯誤的事實。

基本上有兩種常見的「好」這取決於你認爲什麼是「指數」的有效輸入可能性:

  1. 外的界限指標值 預期,是考慮有效的輸入。在 哪種情況下,您應該像在example1中那樣明確地測試並處理它 。在這種情況下,您不需要拋出任何異常。

  2. 越界索引意外(並因此是調用代碼中的錯誤)。你的代碼應該在這裏引發異常。如果你喜歡,你可以用自己的消息來捕獲並重新拋出異常,但是你也可以讓IndexOutOfBounds異常傳播。不要擔心這種異常處理對性能的影響 - 您剛剛發現了一個錯誤,因此您希望程序儘快並且「大聲」地發生故障.....

+1

很好的答案。但我認爲打印到標準輸出只是爲了演示不同的用例。 – Dunes

2

I don看看指數如何超出界限一直是一個正常情況。要麼你的算法有錯誤,要麼你沒有正確地驗證輸入。在這種情況下驗證輸入包括檢查索引是否在邊界內。使用if(與您的第一個片段中的內容一樣)進行檢查顯然比捕獲異常更具可讀性,清潔性和高效性。

+0

在解碼網絡數據包時,數組的索引通常是根據數據包本身中的數據計算得出的,這些數據可能已損壞。代碼需要妥善處理形成不良的數據包。在C代碼中不這樣做通常是許多安全漏洞的基礎。 – AlanObject

+0

是的。這就是我所說的「驗證輸入」。這裏的輸入是從數據計算的指數。如果您必須正常處理損壞的數據包,請檢查索引是否處於邊界內,然後採取相應措施。但是應該使用if語句來實現檢查,而不是通過捕獲IndexOutOfBoundsException。 –