1. 程式人生 > >Java虛擬機器結構詳解

Java虛擬機器結構詳解

1   JVM整體架構

2   JVM類載入器

3   JVM記憶體結構

4   JVM執行引擎

1  JVM整體架構

•   JVM(虛擬機器):指以軟體的方式模擬具有完整硬體系統功能、執行在一個完全隔離環境中的完整計算機系統 ,是物理機的軟體實   現。常用的虛擬機器有VMWare,Virtual Box,Java Virtual Machine

•   Java虛擬機器陣營:Sun HotSpot VM、BEA JRockit VM、IBM J9 VM、Azul VM、Apache Harmony、Google Dalvik VM、  Microsoft JVM...

JVM由三個主要的子系統構成

       •類載入器子系統

       •執行時資料區(記憶體結構)

       •執行引擎

Java執行時編譯原始碼(.java)成位元組碼,由jre執行。jre由java虛擬機器(jvm)實現。Jvm分析位元組碼,後解釋並執行

類載入過程

類載入過程

類載入:類載入器將class檔案載入到虛擬機器的記憶體

•  載入:在硬碟上查詢並通過IO讀入位元組碼檔案

•  連線:執行校驗、準備、解析(可選)步驟

•  校驗:校驗位元組碼檔案的正確性

•  準備:給類的靜態變數分配記憶體,並賦予預設值

•  解析:類裝器裝入類所引用的其他所有類

•  初始化:對類的靜態變數初始化為指定的值,執行靜態程式碼塊

類載入器種類

•  啟動類載入器:負責載入JRE的核心類庫,如jre目標下的rt.jar,charsets.jar等

•  擴充套件類載入器:負責載入JRE擴充套件目錄ext中JAR類包

•  系統類載入器:負責載入ClassPath路徑下的類包

•  使用者自定義載入器:負責載入使用者自定義路徑下的類包

類載入機制

•    全盤負責委託機制當一個ClassLoader載入一個類時,除非顯示的使用另一個ClassLoader,該類所依賴和引用的類也由這    個ClassLoader載入

•    雙親委派機制

:指先委託父類載入器尋找目標類,在找不到的情況下自己的路徑中查詢並載入目標類

雙親委派模式優勢

•  沙箱安全機制:自己寫的String.class類不會被載入,這樣便可以防止核心API庫被隨意篡改

•  避免類的重複載入當父親已經載入了該類時,就沒有必要子ClassLoader再   載入一次

JVM記憶體結構

本地方法棧(執行緒私有)登記native方法,在Execution Engine執行時載入本地方法庫

程式計數器執行緒私有就是一個指標,指向方法區中的方法位元組碼(用來儲存指向下一條指令的地址,也即將要執行的指令程式碼),由執行引擎讀取下一條指令,是一個非常小的記憶體空間,幾乎可以忽略不記。

方法區(執行緒共享)類的所有欄位和方法位元組碼,以及一些特殊方法如建構函式,介面程式碼也在此定義。簡單說,所有定義的方法的資訊都儲存在該區域,靜態變數+常量+類資訊(構造方法/介面定義)+執行時常量池都存在方法區中,雖然Java虛擬機器規範把方法區描述為堆的一個邏輯部分,但是它卻有一個別名叫做 Non-Heap(非堆),目的應該是與 Java 堆區分開來。

Java棧(執行緒私有 Java執行緒執行方法的記憶體模型一個執行緒對應一個棧,每個方法在執行的同時都會建立一個棧幀(用於儲存區域性變量表,運算元棧,動態連結,方法出口等資訊不存在垃圾回收問題,只要執行緒一結束該棧就釋放,生命週期和執行緒一致

JVM對該區域規範了兩種異常:

1) 執行緒請求的棧深度大於虛擬機器棧所允許的深度,將丟擲StackOverFlowError異常

2) 若虛擬機器棧可動態擴充套件,當無法申請到足夠記憶體空間時將丟擲OutOfMemoryError,通過jvm引數Xss指定棧空間,空間大小決定函式呼叫的深度

例項詳解Java棧

JVM記憶體結構

++方法區的互動關係

HotSpot是使用指標的方式來訪問物件

Java堆中會存放訪問類元資料的地址

reference儲存的就直接是物件的地址

(執行緒共享):虛擬機器啟動時建立,用於存放物件例項,幾乎所有的物件(包含常量池)都在堆上分配記憶體,當物件無法再該空間申請到記憶體時將丟擲OutOfMemoryError異常。同時也是垃圾收集器管理的主要

新生區

類誕生、成長、消亡的區域,一個類在這裡產生,應用,最後被垃圾回收器收集,結束生命。

新生區分為兩部分: 伊甸區(Eden space)和倖存者區(Survivor pace) ,所有的類都是在伊甸區被new出來的。倖存區有兩個: 0區(Survivor 0 space)和1區(Survivor 1 space)。當伊甸園的空間用完時,程式又需要建立物件,JVM的垃圾回收器將對伊甸園區進行垃圾回收(Minor GC),將伊甸園區中的不再被其他物件所引用的物件進行銷燬。然後將伊甸園中的剩餘物件移動到倖存 0區。若倖存 0區也滿了,再對該區進行垃圾回收,然後移動到1區。那如果1區也滿了呢?

老年區

新生區經過多次GC仍然存活的物件移動到老年區。若老年區也滿了,那麼這個時候將產生MajorGCFullGC,進行老年區的記憶體清理。若老年區執行了Full GC之後發現依然無法進行物件的儲存,就會產生OOM異常“OutOfMemoryError

元資料區

元資料區取代了永久代(jdk1.8以前),本質和永久代類似,都是JVM規範中方法區的實現,區別在於元資料區並不在虛擬

機中,而是使用本地實體記憶體,永久代在虛擬機器中,永久代邏輯結構上屬於堆,但是物理上不屬於堆,

堆大小=新生代+老年代。元資料區也有可能發生OutOfMemory異常。

Jdk1.6及之前: 有永久代, 常量池在方法區

Jdk1.7:       有永久代,但已經逐步“去永久代”,常量池在堆

Jdk1.8及之後: 無永久代,常量池在元空間

元資料區的動態擴充套件

預設XX:MetaspaceSize值為21MB的高水位線。一旦觸及則Full GC將被觸發並解除安裝沒有用的

類(類對應的類載入器不再存活),然後高水位線將會重置。新的高水位線的值取決於GC後釋放的元空間。如果釋放

的空間少,這個高水位線則上升。如果釋放空間過多,則高水位線下降。

為什麼jdk1.8用元資料區取代了永久代?

官方解釋:移除永久代是為融合HotSpot JVMJRockit VM而做出的努力,因為JRockit沒有永久代,不需要配置永久代

JVM執行引擎

執行引擎:

讀取執行時資料區的Java位元組碼並逐個執行