天天看點

JVM執行模式

解釋執行和編譯執行

解釋執行

解釋執行:通過解釋器将源語言代碼逐條解釋成機器語言,然後送出給計算機執行,解釋一條執行一條,不形成目标程式,不依賴于平台

如在終端上打一條指令或語句,解釋程式就立即将此語句解釋成一條或幾條指令并送出硬體立即執行且将執行結果反映到終端,從終端把指令打入後,就能立即得到計算結果。這種工作方式很适合于人通過終端裝置與計算機互動。

缺點:解析需要時間,不生成目标程式,而是一句一句的執行的方式會造成計算機資源的浪費,即執行效率低。

編譯執行

編譯執行:由編譯器将目标代碼一次性全部編譯成目标程式,再由機器運作目标程式。相比解釋執行編譯執行效率高,占用資源小,适合複雜程式。

編譯過程是:先分析(詞法分析和文法分析),後綜合(優化代碼,存儲配置設定和目标代碼生成),進而得到目标程式。為了完成這些分析綜合任務,編譯程式采用對源程式進行多次掃描的辦法,每次掃描集中完成一項或幾項任務,也有一項任務分散到幾次掃描去完成的。編譯的過程需要花費時間,編譯後的機器碼具有平台相關性,運作速度快。

缺點:相容性差

通俗的比喻

編譯執行相當于做好一桌子菜再開吃,而解釋執行就是吃火鍋,一邊煮一邊吃。

JVM的執行模式

java通常java分為編譯期和運作時。編譯期就是通過​

​javac​

​編譯器将java源代碼檔案生成​

​.class​

​檔案,​

​.class​

​檔案裡面實際上是位元組碼,而不是可以執行的機器碼。運作時,JVM 會通過類加載器(Class-Loader)加載位元組碼,解釋或者編譯執行。啟動JVM時加上​

​-XX:PrintCompilation​

​參數能看到相關的資訊。

Java 是解釋執行?

對于​

​Java 是解釋執行的​

​這個說法其實不太準确。java的源代碼首先通過​

​javac​

​編譯器編譯成位元組碼(bytecode),然後在運作時,通過JVM内嵌的解釋器将位元組碼轉換成最終的機器碼,這時候看起來是解釋執行的,但是常見的JVM(例如HotSpot JVM)都提供了JIT(Just-In-Time)編譯器(即動态編譯器),它能夠在運作時将熱點代碼編譯成機器碼,然後緩存在codecach中,需要的時候直接去codecach中取即可,而不用再次編譯。這種情況下這些熱點代碼就屬于編譯執行而不是解釋執行。

JVM的四種種執行模式

JVM目前支援四種執行模式:

  • 解釋模式
  • 編譯模式
  • 混合模式
  • AOT(Ahead-of-Time Compilation)

    在JVM啟動時,可以指定不同的參數選擇不同的執行模式。新版本的JDK(例如JDK8)預設采用的是混合模式。

JVM啟動時,指定​

​-Xint​

​參數,就是告訴JVM隻進行解釋執行,不對代碼進行編譯。這種模式抛棄了JIT可能帶來的性能優勢。畢竟解釋器是逐條讀入,逐條解釋執行的。

​-Xcomp​

​參數,就是告訴JVM關閉解釋器,使用編譯模式(或者叫最大優化級别),不進行解釋執行。這種模式并不表示執行效率最高,它會導緻JVM啟動變得非常慢,同時有些JIT編譯器的優化操作(如分支預測)并不能進行有效的優化。

混合模式,就是解釋和編譯混合的一種模式,新版本的JDK(例如JDK8)預設采用的是混合模式(JVM參數為​

​-Xmixed​

​)。通常運作在server模式的JVM,會進行上萬次調用以收集足夠的資訊進行高效的編譯,client模式這個限制是1500次。Hotspot JVM内置了兩個不同的JIT編譯器,C1對應client模式,适用于對于啟動速度敏感的應用(如java桌面應用);C2對應server模式,它的優化是為長時間運作的伺服器端應用設計的。

AOT就是将javac編譯器編譯後的位元組碼直接編譯成機器代碼,避免了JIT預熱等各方面的開銷。Oracle JDK 9就引入了實驗性的AOT特性,并增加了新的jaotc工具。

将某個類或者摸個子產品編譯成AOT庫

jaotc --output libHelloWorld.so Helloworld.class  
jaotc --output libjava.base.so --module java.base

在啟動的時候直接指定

java -XX:AOTLibrary=./libHelloWorld.so,libjava.base.so HelloWorld