在HotSpot VM中內嵌有兩個JIT編譯器,分別為Client Compiler和Server Compiler,通常簡稱為C1編譯器和C2編譯器。開發人員可以通過如下命令顯式指定JVM在運行時到底使用哪一種即時編譯器。(1)-client:指定JVM運行在Client模式下,并使用C1編譯器。C1編譯器會對字節碼進行簡單和可靠的優化,耗時短,以達到更快的編譯速度。
(2)-server:指定JVM運行在Server模式下,并使用C2編譯器。C2進行耗時較長的優化,以及激進優化,但優化的代碼執行效率更高。在不同的編譯器上有不同的優化策略,C1編譯器上主要有方法內聯,去虛擬化、冗余消除。(1)方法內聯:將引用的函數代碼編譯到引用點處,這樣可以減少棧幀的生成,減少參數傳遞以及跳轉過程。(2)去虛擬化:對唯一的實現類進行內聯。(3)冗余消除:在運行期間把一些不會執行的代碼折疊掉。C2的優化主要是在全局層面,逃逸分析是優化的基礎。基于逃逸分析在C2上有如下幾種優化。(1)標量替換:用標量值代替聚合對象的屬性值。(2)棧上分配:對于未逃逸的對象分配對象在棧而不是堆。(3)同步消除:清除同步操作,通常指synchronized。Java分層編譯(Tiered Compilation)策略:不開啟性能監控的情況下,程序解釋執行可以觸發C1編譯,將字節碼編譯成機器碼,可以進行簡單優化。如果開啟性能監控,C2編譯會根據性能監控信息進行激進優化。不過在Java 7版本之后,一旦開發人員在程序中顯式指定命令“-server”時,默認將會開啟分層編譯策略,由C1編譯器和C2編譯器相互協作共同來執行編譯任務。一般來講,JIT編譯出來的機器碼性能比解釋器高。C2編譯器啟動時長比C1編譯器慢,系統穩定執行以后,C2編譯器執行速度遠遠快于C1編譯器。默認情況下HotSpot VM則會根據操作系統版本與物理機器的硬件性能自動選擇運行在哪一種模式下,以及采用哪一種即時編譯器。