2019獨角獸企業重金招聘Python工程師標準>>>
JVM 架構解釋
每個Java開發者都知道通過JRE【Java運行環境】執行字節碼。
但是很多人都不知道JRE是JVM實現的事實。JVM負責執行字節碼的分析
代碼的解釋和運行。
我們應該了解JVM的架構,這對開發者來說是很重要的,這促進我們更有效的
編寫代碼。在本文中,我們將深入學習有關JVM的架構和JVM組件的區別。
什么是JVM?
虛擬機是物理機的一個軟件實現。
JAVA是基于WORA(一次編寫,到處運行)的概念開發的,它運行在虛擬機上。
編譯器將Java文件編譯成class文件,然后將class文件輸入到JVM,JVM加載并運行class文件。
下面是JVM架構圖:
JVM是如何工作的?
像上面圖表顯示那樣,JVM分成3個主要的子系統:
- 類加載器子系統
- 運行時數據區
- 執行引擎
?
1、類加載器子系統
Java的動態類加載功能是通過類加載子系統去處理的。
它并不是在編譯時候,而是在首次運行時加載引用類時、連接并初始化類文件。
?
1.1 加載
類通過該組件加載。通過引導類加載器,擴展類加載器,應用類加載器這三個類加載器幫助完成加載。
- 引導類加載器
負責從引導類路徑去加載類,除了rt.jar之外,沒其他別的jar。給予該加載器最高的優先級。
- 擴展類加載器
負責加載ext目錄(jre\lib)的類
- 應用加載器
負責加載類路徑中應用級別的類,path提到的環境變量,等等。
以上的類加載器在加載類文件的時候遵循委托層次算法。
1.2連接
- 驗證-字節碼驗證器驗證生成的字節碼是否正確,如果驗證失敗,我們將收到驗證的錯誤信息。
- 準備-為所有的靜態變量分配內存和默認值
- 解析-用方法區的原始引用代替所有符號內存引用。
?
1.3 初始化
這是類加載的最后一個階段,此時所有的靜態變量都用原始值去賦值,并且將運行靜態代碼塊。
2、運行時數據區
運行時數據區域分成5個主要的組件:
- 方法區-所有類級的數據都存儲在這里,包括靜態變量。
每個JVM只有一個方法區,它是一個共享資源。
- 堆區-所有的對象和對應的實例變量以及數組都存儲在這里。
每個JVM只有一個堆區,由于方法區和堆區為多個線程共享內存,所以
存儲的數據不是線程安全的。
- 棧區-為每個線程,創建一個單獨的運行時棧。為每個方法調用,在棧內存創建一個條目,稱之為棧幀。所有本地變量都會在棧內存中創建。由于它不是共享的資源,所有是線程安全的。
棧幀被分成3子實體
- 本地變量數組-涉及跟方法有關的本地變量和對應的值都存儲在這里。
- 操作數棧-如果需要執行中間操作,操作數堆棧作為運行時工作區來執行操作。
- 幀數據-所有和對應方法的標記都存儲在里面。在發生異常的情況下,捕捉塊信息在這里維護。
- 程序計數器寄存器--每個線程都有自己的程序計數器寄存器,持有當前執行指令的地址,一旦當前指令執行被運行,下一個指令將會更新到程序計數器寄存器。
3、執行引擎
字節碼被分配到執行引擎執行的運行時數據區。執行引擎一塊一塊的讀取字節碼并執行。
- 解釋器-解釋器解釋字節碼很快,但是執行的很慢。解釋器的缺點是當一個方法被調用多次,每次都需要一個新的解釋。
- JIT編譯器-JIT彌補了解釋器的缺點。執行引擎將利用解釋器轉換字節碼,但是當他找到重復的編碼,它就使用編譯器。編譯器編譯全部的字節碼并變成本地代碼
這些本地碼將直接被方法調用重復地使用,這就改善了系統的性能。
- 中間代碼生成器-生成中間代碼。
- 代碼優化器-負責優化上面生成的代碼
- 目標代碼生成器-負責生成機器碼或者本地代碼
- 分析器-一個特殊的組件,負責尋找hotspots,即是否方法被調用多次。
?
- 垃圾收集器:收集和清除未被引用的對象,可以通過System.gc()觸發垃圾回收,但是不保證一定執行。創建收集對象的JVM垃圾收集。
?
Java Native Interface (JNI):JNI和本地方法庫互動,特供本地庫所需的執行引擎。
Native Method Libraries: 這是執行引擎所需的本地方法的一個集合
?
本文為在下翻譯外文的處女作,水平有限,翻譯不恰當之處,煩請讀者指正!
原文地址:https://dzone.com/articles/jvm-architecture-explained
?