什麼是 Java 字節碼?採用字節碼的好處是什麼?

在 Java 中,JVM 可以理解的代碼就叫做字節碼(即擴展名爲 .class 的文件),它不面向任何特定的處理器,只面向虛擬機。Java 語言通過字節碼的方式,在一定程度上解決了傳統解釋型語言執行效率低的問題,同時又保留了解釋型語言可移植的特點。所以, Java 程序運行時相對來說還是高效的(不過,和 C++,Rust,Go 等語言還是有一定差距的),而且,由於字節碼並不針對一種特定的機器,因此,Java 程序無須重新編譯便可在多種不同操作系統的計算機上運行。

Java 程序從源代碼到運行的過程如下圖所示:

Java程序轉變爲機器代碼的過程

我們需要格外注意的是 .class->機器碼 這一步。在這一步 JVM 類加載器首先加載字節碼文件,然後通過解釋器逐行解釋執行,這種方式的執行速度會相對比較慢。而且,有些方法和代碼塊是經常需要被調用的(也就是所謂的熱點代碼),所以後面引進了 JIT(just-in-time compilation) 編譯器,而 JIT 屬於運行時編譯。當 JIT 編譯器完成第一次編譯後,其會將字節碼對應的機器碼保存下來,下次可以直接使用。而我們知道,機器碼的運行效率肯定是高於 Java 解釋器的。這也解釋了我們爲什麼經常會說 Java 是編譯與解釋共存的語言

HotSpot 採用了惰性評估(Lazy Evaluation)的做法,根據二八定律,消耗大部分系統資源的只有那一小部分的代碼(熱點代碼),而這也就是 JIT 所需要編譯的部分。JVM 會根據代碼每次被執行的情況收集信息並相應地做出一些優化,因此執行的次數越多,它的速度就越快。JDK 9 引入了一種新的編譯模式 AOT(Ahead of Time Compilation),它是直接將字節碼編譯成機器碼,這樣就避免了 JIT 預熱等各方面的開銷。JDK 支持分層編譯和 AOT 協作使用。

爲什麼不全部使用 AOT 呢?

AOT 可以提前編譯節省啓動時間,那爲什麼不全部使用這種編譯方式呢?

長話短說,這和 Java 語言的動態特性有千絲萬縷的聯繫了。舉個例子,CGLIB 動態代理使用的是 ASM 技術,而這種技術大致原理是運行時直接在內存中生成並加載修改後的字節碼文件也就是 .class 文件,如果全部使用 AOT 提前編譯,也就不能使用 ASM 技術了。爲了支持類似的動態特性,所以選擇使用 JIT 即時編譯器。

相關閱讀:Java基礎常見面試題總結(上)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章