以前有句話說:“Java是解釋執行的 ” 。現在看來確實不是很准確,至於原因,在此簡略解釋:
首先,我們先解釋一下在Java中解釋執行和編譯執行的區別。
解釋執行:將編譯好的字節碼一行一行地翻譯為機器碼執行。
編譯執行:以方法為單位,將字節碼一次性翻譯為機器碼后執行。
在編譯示時期,我們通過將源代碼編譯成.class ,配合JVM這種跨平台的抽象,屏蔽了底層計算機操作系統和硬件的區別,實現了“一次編譯,到處運行” 。 而在運行時期,目前主流的JVM 都是混合模式(-Xmixed),即解釋運行 和編譯運行配合使用。
以 Oracle JDK提供的HotSpot虛擬機為例,在HotSpot虛擬機中,提供了兩種編譯模式:解釋執行 和 即時編譯(JIT,Just-In-Time)。解釋執行即逐條翻譯字節碼為可運行的機器碼,而即時編譯則以方法為單位將字節碼翻譯成機器碼(上述提到的“編譯執行”)。前者的優勢在於不用等待,后者則在實際運行當中效率更高。
即時編譯存在的意義在於它是提高程序性能的重要手段之一。根據“二八定律”(即:百分之二十的代碼占據百分之八十的系統資源),對於大部分不常用的代碼,我們無需耗時間將之編譯為機器碼,而是采用解釋執行的方式,用到就去逐條解釋運行;對於一些僅占據小部分的熱點代碼(可認為是反復執行的重要代碼),則可將之翻譯為符合機器的機器碼高效執行,提高程序的效率,此為運行時的即時編譯。
為了滿足不同的場景,HotSpot虛擬機內置了多個即時編譯器:C1,C2與Graal。Graal 是Java10正式引入的實驗性即時編譯器,在此暫不敘述(其實我不是很了解,尷尬···)。先看一下C1、C2 ,相信大家或多或少接觸過。
C1:即Client編譯器,面向對啟動性能有要求的客戶端GUI程序,采用的優化手段比較簡單,因此編譯的時間較短。
C2:即Server編譯器,面向對性能峰值有要求的服務端程序,采用的優化手段復雜,因此編譯時間長,但是在運行過程中性能更好。
從Java7開始,HotSpot虛擬機默認采用分層編譯的方式:熱點方法首先被C1編譯器編譯,而后 熱點方法中的熱點再進一步被C2編譯(理解為二次編譯,根據前面的運行計算出更優的編譯優化)。為了不干擾程序的正常運行,JIT編譯時放在額外的線程中執行的,HotSpot根據實際CPU的資源,以 1:2的比例分配給C1和C2線程數。在計算機資源充足的情況,字節碼的解釋運行和編譯運行時可以同時進行,編譯執行完后的機器碼會在下次調用該方法時啟動,已替換原本的解釋執行(意思就是已經翻譯出效率更高的機器碼,自然替換原來的相對低效率執行的方法)。
以上,可以看出在Java中不單單是解釋執行,即時編譯(編譯執行)在Java性能優化中彰顯重要的作用,所以現在應該說:Java是解釋執行和編譯執行共同存在的,至少大部分是這樣。
PS:1. 如有錯誤,請務必指出,以免誤導他人。
2. 第一次寫博客,寫得簡陋,還請多多見諒。希望能鞏固知識,分享知識,共同進步。
