2013-03-06 64 views
47

已知存在使用工具的JDK7編譯代碼的兼容性問題。 至於http://www.oracle.com/technetwork/java/javase/compatibility-417013.html使用-XX有多安全:-UseSplitVerifier?

類文件的版本號51是專門使用已驗證的類型檢查覈實,因此,方法必須具有適當的時候StackMapTable屬性。對於版本爲50的類文件,如果文件中的堆棧映像丟失或不正確,則Hotspot JVM將(並繼續)故障轉移到類型 - 推理驗證器。對於具有版本51(Java SE 7的默認版本)的類文件,不會發生此故障轉移行爲。 任何修改版本51類文件中的字節碼的工具都必須確保將堆棧映射信息更新爲與字節碼一致以便通過驗證。

的解決方案是使用-XX:-UseSplitVerifier作爲總結如下: http://weblogs.java.net/blog/fabriziogiudici/archive/2012/05/07/understanding-subtle-new-behaviours-jdk-7

其安全性如何?我猜想甲骨文已經把這張支票放了一個原因。如果我不使用它,我可能冒着其他一些問題冒險。

什麼是使用-XX:-UseSplitVerifier的後果?

謝謝,

Piotr。

+6

作爲未來讀者的延伸和可能的後果,但在Java8中,該標誌已被棄用。閱讀[this](http://mail.openjdk.java.net/pipermail/hotspot-runtime-dev/2013-March/006287.html)瞭解詳情。 – kurtzbot 2013-07-18 20:34:17

回答

13

在Java 7中添加了堆棧映射框架,「prashant」認爲該想法存在缺陷,並建議開發人員始終使用-XX:-UseSplitVerifier標誌來避免使用它們。

瞭解更多:Java 7 Bytecode Verifier: Huge backward step for the JVM

+0

那麼這是否意味着驗證者沒有在Java 7中運行?或者只有部分是被執行的,而其他的(如文章所說的)現在應該由編譯器來管理? – 2014-01-07 10:01:53

+0

@DinisCruz驗證程序始終運行。使用-XX:-UseSplitVerifier告訴jvm使用2次傳遞方法,該方法比新的默認值稍慢 - 只運行引用StackMap表數據的第二遍。換句話說,第一遍總是由編譯器運行 - 並且運行時會再次執行第一遍,或者它使用編譯器存儲在StackMap表中的中間結果。 – 2014-02-28 19:43:37

54

總之,這是完全安全的。

自Java 6以來,Oracle的編譯器已經使用StackMapTable創建了類文件。其基本思想是編譯器可以明確指定對象的類型,而不是讓運行時執行它。這在運行時提供了一個微小的加速,以換取編譯期間的一些額外時間以及編譯後的類文件(前面提到的StackMapTable)中的一些複雜性。

作爲一個實驗性功能,它在Java 6編譯器中並未默認啓用。如果不存在StackMapTable,則運行時默認會驗證對象類型本身。

直到Java 7. Oracle強制要求:編譯器生成它們,然後運行時驗證它們。如果StackMapTable不在那裏,它仍然使用舊的驗證器......但只在來自Java 6或更早的版本(版本50)的類文件中。 Java 7類文件(版本51)需要使用StackMapTable,因此運行時不會將它們剪切成相同的鬆弛。

這只是一個問題,如果您的類文件沒有生成StackMapTable。例如,如果您使用了非Oracle JVM。或者,如果你之後與字節碼混淆 - 就像使用調試器,優化器或代碼覆蓋率分析器一樣。

但你可以解決它! Oracle的JVM提供了-XX:+ UseSplitVerifier來強制運行時回退到舊的驗證器。它不關心StackMapTable。

實際上,運行速度和效率方面的希望優化還沒有實現:如果存在,它還不足以讓任何人注意到。由於新型驗證器不提供任何新功能(只是優化),關閉它是完全安全的。

Oracle的解釋是在http://www.oracle.com/technetwork/java/javase/compatibility-417013.html如果搜索JSR 202

+2

是的,StackMapTable是Sun的一部分。除此之外,如果他們只嘗試(或問我),他們可以極大地提高舊驗證者的速度。 – 2014-09-28 12:58:16

+0

Minor nitpick,它是'-XX:-UseSplitVerifier'而不是'-XX:+ UseSplitVerifier'。但我想現在無所謂了,因爲它在Java 8中被刪除了。 – imgx64 2015-12-27 04:45:05

24

是 - 它是安全的。正如Judebert所說,它只是略微減緩了課堂上的負荷。

要添加更多信息:什麼是StackMap表?那麼,Bytecode校驗器需要對類文件中的代碼進行兩次傳遞,以驗證傳遞和使用的正確類型的數據。第一遍是較慢的,它對所有代碼的分支進行流分析,以查看每個字節碼指令在棧上的數據類型。第二遍查看每條指令,看看它是否可以在所有類型上有效運行。

下面是關鍵:編譯器已經擁有了第一遍生成的所有信息 - 所以(在Java 6中)將它存儲在類文件中的StackMap表中。

這加快了類加載的速度,因爲類加載器不必這樣做第一遍。這就是爲什麼它被稱爲分割驗證器的原因,因爲工作是在編譯器和運行時加載機制之間分開的。當你使用-XX:-UseSplitVerifier選項時,你告訴Java做這兩個都在類加載時通過(並忽略任何StackMap表)。許多產品(如加載時修改字節碼的分析器)最初並不知道StackMap表,所以當他們在加載時修改類時,編譯器的StackMap表已經過時並導致錯誤。總結一下,-XX:-UseSplitVerifier選項減緩了類的加載速度。它不影響安全性,運行時性能或功能。

+3

+1用於解釋StackMap表的理由。從StackMap表的所有搜索頁面中,這是我發現的最簡單,準確和清晰的說明。 – Sankalp 2014-04-21 11:18:35

+0

這不僅僅是驗證者必須做兩遍。當涉及到(可能是嵌套的)循環和/或(可能嵌套的)異常處理程序時,第一步可能意味着相同代碼的任意數量的傳遞,因爲相同的代碼可能以不同的先決條件執行,並且驗證者必須找出什麼是常見的。這也可能暗示爲兩種或更多類型的最具體的通用基類型搜索類和接口層次結構。 – Holger 2015-07-22 15:10:05