1. 程式人生 > >1.Java平臺的理解-JIT

1.Java平臺的理解-JIT

第一講:

1.Java語言的兩大特性

  • 一次編譯,到處執行(Compile once,run anywhere),具有跨平臺的能力。
  • 垃圾回收(GC,Garbage Collection),Java通過垃圾收集器(Garbage Collection)回收分配記憶體,程式設計師不需要操心記憶體的分配和回收

2.Java開發環境

  • JRE:Java Runtime Enviroment,Java執行時環境,執行Java程式的必需條件,包括Java虛擬機器,Java核心類庫和支援檔案。如果只是執行Java程式,只需要安裝JRE就可以了。
  • JDK:Java Development Kit,是完整的Java軟體開發包,包含了JRE,編譯器和其他的工具(比如:JavaDoc,Java偵錯程式),可以讓開發者開發、編譯、執行Java應用程式。

3.Java是解釋執行的分析

對於“Java是解釋執行”這句話,這個說法不太準確。

原始檔.Java檔案–通過Javac編譯–二進位制的.class檔案(位元組碼[byte code],與平臺無關)–JVM(Java虛擬機器)直譯器–特定平臺機器碼[machine code]。

Java的編譯器先將其編譯為class檔案,也就是位元組碼,這一步稱為Javac編譯;然後將位元組碼交由jvm(java虛擬機器)解釋執行,因而很多地方說“java是一種半編譯、半解釋執行”的語言。現在由於JIT的出現,這種說法有部分是錯誤的。

常見的JVM,比如我們大多數情況使用的OracleJDK 提供的HotspotJVM,都提供了JIT(Just-In-Time)編譯器,也就是通常所說的動態編譯器,JIT能夠在執行時將熱點程式碼編譯成機器碼,這種情況下部分熱點程式碼就屬於編譯執行,而不是解釋執行了。

首先javac編譯器將原始碼編譯成位元組碼。然後jvm 類載入器載入位元組碼檔案,然後通過直譯器逐行解釋執行,這種方式的執行速度相對會比較慢。有些方法和程式碼塊是高頻率呼叫的,也就是所謂的熱點程式碼,所以引進jit技術,
提前將這類位元組碼直接編譯成本地機器碼。這樣類似於快取技術,執行時再遇到這類程式碼直接可以執行,而不是先解釋後執行。

在執行時JIT會把翻譯過的機器碼儲存起來,已備下次使用,因此從理論上來說,採用該JIT技術可以,可以接近以前純編譯技術。

上面所說的,不管是解釋執行還是編譯執行,前提都是Javac編譯器將原始碼編譯成位元組碼,然後再去判斷是否開啟JIT。

4.知識擴充套件

對於Java平臺的理解,可以從以下很多方面進行概括:

  • Java語言特性,包括泛型、Lambda等語言特性
  • 基礎類庫:包括集合、IO/NIO、網路、併發、安全等等
  • JVM的一些基礎概念和機制
    • 類載入機制:常用版本JDK內嵌的Class-Loader,例如Bootstrap、Application和Extension Class-loader
    • 類載入過程:載入、驗證、連結、初始化
    • 垃圾回收的基本原理,最常見的垃圾收集器:Serial GC、Parallel GC、CMS、G1等等
  • JDK包含的工具或者Java領域內的其他工具,如編譯器、執行時環境、安全工具、診斷和監控工具。

5.Java跨平臺的解析

  • 我們通常把Java分為編譯期和執行時。這裡說的Java的編譯和C/C++是有著不同的意義的,Javac的編譯,編譯Java原始碼生成“.class”檔案裡面實際是位元組碼,而不是可以直接執行的機器碼。Java通過位元組碼和Java虛擬機器(JVM)這種跨平臺的抽象,遮蔽了作業系統和硬體的細節,這也是實現“一次編譯,到處執行”的基礎。
  • 編譯後的位元組碼與平臺無關,所以Java所謂的跨平臺就是在不同平臺上安裝了不同的jvm,而在不同平臺上生成的.class檔案都是一樣的,而.class檔案再由對應平臺的jvm解釋成對應平臺的機器碼執行。它首先將原始碼編譯成位元組碼,然後依賴各種不同平臺上的虛擬機器來解釋執行位元組碼,從而實現了“一次編寫,到處執行”的跨平臺特性。
  • 在執行時,JVM 會通過類載入器(Class-Loader)載入位元組碼,解釋或者編譯執行。就像我前面提到的,主流Java版本中,如JDK8實際是解釋和編譯混合的一種模式,即所謂的混合模式(-Xmixed)。通常執行在server模式的JVM,會進行上萬次呼叫以收集足夠的資訊進行高效的編譯,client模式這個門限是1500次。Oracle Hotspot JVM 內建了兩個不同的JITcompiler,C1對應前面說的client模式,適用於對於啟動速度敏感的應用,比如普通Java桌面應用;C2對應server模式,它的優化是為長時間執行的伺服器端應用設計的。預設是採用所謂的分層編譯(TieredCompilation)。
  • Java虛擬機器啟動時,可以指定不同的引數對執行模式進行選擇。比如,指定“-Xint”,就是告訴JVM 只進行解釋執行,不對程式碼進行編譯,這種模式拋棄了JIT可能帶來的效能優勢。畢竟直譯器(interpreter)是逐條讀入,逐條解釋執行的。與其相對應的,還有一個“-Xcomp”引數,這是告訴JVM 關閉直譯器,不要進行解釋執行,或者叫作最大優化級別。那你可能會問這種模式是不是最高效啊?簡單說,還真未必。“-Xcomp”會導致JVM 啟動變慢非常多。
  • 除了我們日常最常見的Java使用模式,其實還有一種新的編譯方式,即所謂的AOT(Ahead-of -TimeCompilation),直接將位元組碼編譯成機器程式碼,這樣就避免了JIT預熱等各方面的開銷,比如Oracle JDK9就引入了實驗性的AOT特性,並且增加了新的jaotc工具。
  • 推薦博文 深入理解java虛擬機器(十三) Java 即時編譯器JIT機制以及編譯優化