Java 7 剛剛釋出沒兩天,但來自 Lucene 和 Solr 社群的某些人立即報料了一些 Java 7 中的嚴重bug。甚至 Apache Lucene 專案管理委員會成員 Uwe Schindler 釋出了暫時不要使用 Java 7 的警告資訊。 那麼到底 Java 7 是有什麼問題,為什麼我們等了 5 年的 Java 7 現在卻不能使用呢?讓我們來看看實際的情況。
這個問題跟 Java 7 無關,而是跟 JVM 有關
首先這個問題是跟 HotSpot JVM 有關,而不是 Java 7 語言本身的問題。此次釋出的 GA 版本包含三個bug:7070134, 7044738 和 7068051 ,這三個bug直接導致 JVM 崩潰或者進行錯誤的計算。
Hotspot 是因為 PorterStemmer 的 sigsegv 而崩潰的
第一個問題(7070134) 是關於錯誤的編譯器對迴圈的優化,該特性在 Hotspot JVM 中是預設啟用的,你可以通過 -XX:-UseLoopPredicate 引數來關閉這個特性。如果你想了解關於這個問題的詳情,請看 Stemmer.java ,編譯並允許這個類你將會重現 JVM 崩潰並報嚴重錯誤,資訊如下:
1 |
# A fatal error has been detected by the Java Runtime Environment:## EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00000000026536da, pid=5432, tid=6568## JRE version: 7.0-b135# Java VM: Java HotSpot(TM) 64-Bit Server VM (21.0-b05 mixed mode windows-amd64compressed oops)# Problematic frame:# J Stemmer.step4()V |
這個錯誤直接在程式碼執行過程中發生,在 JDK 1.6 是體驗不到的。而最近 Lucene 做了一些更靈活的基於 PulsingCodec 演算法的索引機制,而這個機制相當大的程度上會導致上述的錯誤。
迴圈展開優化會導致不正確的結果
第二個bug (7044738) 是“錯誤的計算”,這個錯誤極為罕見的發生在 OSR (On-Stack Replacement) 編譯巢狀迴圈上,控制流退出且對應的記憶體沒有被考慮到,這直接導致重複的克隆結果,想了解編譯細節請看 older overview (PDF)
一個最簡單的解決辦法就是使用 -XX:LoopUnrollLimit=1 引數來避免這個問題。
Clone loop predicate during loop unswitch
第三個bug(7068051) 跟一些老的 feature request 相關,由於一些無效的 JVM 統計導致使用迴圈優化後的 JVM 崩潰。
結論
根據這些bug的情況,只有在你大量的使用這些優化方法,那麼你才可能已經受 Java 7 中存在的問題所影響。一般情況下是不受影響的。事實上 Java 6 的使用者使用了某些優化選項也會存在問題,但因為這些優化選項在 Java 7 中是預設啟用的才導致這個問題影響那麼大,例如 (-XX:+OptimizeStringConcat or -XX:+AggressiveOpts) ,由於這些問題在 Java 7 釋出的前 5 天才被發現,因此 Oracle 來不及解決這些bug,目前 Oracle 似乎也正在準備下一個補丁版本,但對一些高階使用者來說,這些都不是問題,因為原始碼是開放的,你可以做你想做的。
原文:eisele.net
譯文:oschina