早在Java1.0版本的時候,Sun公司發佈了一款名爲Sun Classic VM的Java虛擬機,它同時也是世界上第一款商用Java虛擬機,在當時這款虛擬機內部只提供解釋器,用今天的眼光來看待必然是效率低下的,由於若是Java虛擬機只可以在運行時對代碼採用逐行解釋執行,程序的運行性能可想而知。可是現在的HotSpot VM中不只內置有解釋器,還內置有先進的JIT(Just In Time Compiler)編譯器,在Java虛擬機運行時,解釋器和即時編譯器可以相互協做,各自取長補短。在此你們須要注意,不管是採用解釋器進行解釋執行,仍是採用即時編譯器進行編譯執行,最終字節碼都須要被轉換爲對應平臺的本地機器指令。
或許有些開發人員會感受到詫異,既然HotSpot VM中已經內置JIT編譯器了,那麼爲何還須要再使用解釋器來「拖累」程序的執行性能呢?好比JRockit VM內部就不包含解釋器,字節碼所有都依靠即時編譯器編譯後執行,儘管程序的執行性能會很是高效,但程序在啓動時必然須要花費更長的時間來進行編譯。對於服務端應用來講,啓動時間並不是是關注重點,但對於那些看中啓動時間的應用場景而言,或許就須要採用解釋器與即時編譯器並存的架構來換取一個平衡點。
既然HotSpot VM中採用了即時編譯器,那麼這就意味着將字節碼編譯爲本地機器指令是一件運行時任務。在HotSpot VM中內嵌有兩個JIT編譯器,分別爲Client Compiler和Server Compiler,但大多數狀況下咱們簡稱爲C1編譯器和C2編譯器。開發人員能夠經過以下命令顯式指定Java虛擬機在運行時到底使用哪種即時編譯器,以下所示:
-client:指定Java虛擬機運行在Client模式下,並使用C1編譯器;
-server:指定Java虛擬機運行在Server模式下,並使用C2編譯器。
除了能夠顯式指定Java虛擬機在運行時到底使用哪種即時編譯器外,默認狀況下HotSpot VM則會根據操做系統版本與物理機器的硬件性能自動選擇運行在哪種模式下,以及採用哪種即時編譯器。簡單來講,C1編譯器會對字節碼進行簡單和可靠的優化,以達到更快的編譯速度;而C2編譯器會啓動一些編譯耗時更長的優化,以獲取更好的編譯質量。不過在Java7版本以後,一旦開發人員在程序中顯式指定命令「-server」時,缺省將會開啓分層編譯(Tiered Compilation)策略,由C1編譯器和C2編譯器相互協做共同來執行編譯任務。不過在早期版本中,開發人員則只可以經過命令「-XX:+TieredCompilation」手動開啓分層編譯策略。
以前筆者曾經說起過,缺省狀況下HotSpot VM是採用解釋器與即時編譯器並存的架構,固然開發人員能夠根據具體的應用場景,經過命令顯式地爲Java虛擬機指定在運行時究竟是徹底採用解釋器執行,仍是徹底採用即時編譯器執行。以下所示:
-Xint:徹底採用解釋器模式執行程序;
-Xcomp:徹底採用即時編譯器模式執行程序;
-Xmixed:採用解釋器+即時編譯器的混合模式共同執行程序。
在此你們須要注意,若是Java虛擬機在運行時徹底採用解釋器執行,那麼即時編譯器將會中止全部的工做,字節碼將徹底依靠解釋器逐行解釋執行。反之若是Java虛擬機在運行時徹底採用即時編譯器執行,但解釋器仍然會在即時編譯器沒法進行的特殊狀況下介入執行,以確保程序可以最終順利執行。
因爲即時編譯器將本地機器指令的編譯推遲到了運行時,自此Java程序的運行性能已經達到了能夠和C/C++程序一較高下的地步。這主要是由於JIT編譯器能夠針對那些頻繁被調用的「熱點代碼」作出深度優化,而靜態編譯器的代碼優化則沒法徹底推斷出運行時熱點,所以經過JIT編譯器編譯的本地機器指令比直接生成的本地機器指令擁有更高的執行效率也就理所固然了。好比使用Python實現的PyPy執行器,比使用C實現的CPython解釋器更加靈活,更重要的是,在程序的運行性能上進行比較,PyPy將近是CPython解釋器執行效率的1至5倍,這就是對JIT技術魅力的一個有力證實。而且Java技術自身的諸多優點一樣也是C/C++沒法比擬的,所謂各有所長就是這個道理。在此你們須要注意,世界上永遠沒有最好的編程語言,只有最適用於具體應用場景的編程語言。
編程