一、類文件到虛擬機(類加載機制)
1.1 裝載(Load)
類加載的第一步是對類的裝載過程:
1)通過一個類的全限定名獲取定義此類的二進制字節流。
2)將這個字節流代表的靜態存儲結構轉化爲方法區的運行時數據結構
3)在Java堆中生成一個代表這個類的java.lang.Class對象,作爲對方法區中這些數據的訪問入口。
1.2 鏈接(Link)
類加載的第二步是鏈接,鏈接這一步中包含驗證、準備、解析的步驟。
1.2.1 驗證(Verify)
保證被家族類的正確性
文件格式驗證
元數據驗證
字節碼驗證
符號引用驗證
1.2.2 準備(Prepare)
爲類的靜態變量分配內存,並將其初始化爲默認值。
1.2.3 解析(Resolve)
把類中的符號引用轉換爲直接引用。
1.3 初始化(Initialize)
類加載的第三步是初始化操作。
對靜態變量、靜態代碼塊執行初始化操作。
1.4 類加載機制圖解
使用和卸載並不算是類加載過程中的階段,只是畫完整了一點。
二、類裝載器(ClassLoader)
在裝載(Load)階段,其中第一步是通過類的全限定類名獲取其定義的二進制字節流,需要藉助類裝載器完成。顧名思義,就是用來裝載Class文件的。
2.1 分類
1)Bootstrap ClassLoader:負責加載$JAVA_HOME中jir/lib/rt.jar 裏所有的class或Xbootclassoath選項指定的jar包。由C++實現,不是ClassLoader的子類。
2)Extension ClassLoader 負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中 jre/lib/*.jar 或 -Djava.ext.dirs指定目錄下的jar包。
3)App ClassLoader 負責加載classpath中指定的jar包及 Djava.class.path 所指定目錄下的類和jar包。
4)Custom ClassLoader 通過java.lang.ClassLoader的子類自定義加載class,屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader。
2.2 圖解類裝載器
2.3 雙親委派機制
定義:如果一個類加載器在接到加載類的請求時,它首先不會自己去嘗試加載這個類,而是把這個請求任務委託給父類加載器去完成,依次遞歸,如果父類加載器可以完成類加載任務,就成功返回。只有父類加載器無法完成此加載任務時,才自己去加載。
優勢:Java類隨着加載它的類加載器一起具備了一種帶有優先級的層次關係。
比如,Java中的Object類,它存放在rt.jar之中,無論哪一個類加載器要加載這個類,最終都是委派給處於模型最頂端的啓動類加載器進行加載。因此Object在各種類加載環境中都是同一個類。如果不採用雙親委派模型,由各個類加載器自己去加載的話,那麼系統中會存在多個不同的Object類。
破壞:可以繼承ClassLoader類,然後重寫其中的loadClass方法。
三、運行時數據區(Run-Time Data Areas)
在裝載階段的第2、3步可以發現有運行時數據、堆、方法區等名詞。
其實說的就是類文件被類裝載器裝載進來之後,類中的內容(比如變量、常量、方法、對象這些數據)要被存儲起來,存儲的位置肯定是在JVM中有對應的空間。
3.1 圖解
3.2 各部分簡介
3.2.1 Method Area(方法區)
方法區是各個線程共享的內存區域,在虛擬機啓動時創建。
用於存儲已經被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。
當方法區無法滿足內存分配需求時,將拋出OutOfMemoryError異常。
雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,但它又有個別名叫Non-Heap(非堆),目的是和Java堆區分開來。
四、運行時數據區提煉總結
名稱 | 是否線程共享 | 作用 | 可能出現的異常 |
方法區 |
線程共享 |
存放類信息(版本、字段、方法、接口等)、常量、靜態變量、即時編譯後的代碼等數據。 |
內存不足時,拋出OutOfMemoryError(內存不足錯誤)。 |
虛擬機棧 |
線程私有 |
存放局部變量表、操作數據棧、動態鏈接、方法出口等信息。 |
棧幀深度大於允許最大深度時,拋出StackOverflowError(棧溢出錯誤); 內存不足時,拋出OutOfMemoryError(內存不足錯誤) |
堆 |
線程共享 |
存放對象實例和數組。 |
內存不足時,拋出OutOfMemoryError(內存不足錯誤) |
程序計數器 |
線程私有 |
記錄當前線程所執行的字節碼指令。 |
唯一不會出現OutOfMemoryError的區域。 |
本地方法棧 |
線程私有 |
java虛擬機棧類似,不過是爲了JVM用到的Native方法服務。 |
棧幀深度大於允許最大深度時,拋出StackOverflowError(棧溢出錯誤); 內存不足時,拋出OutOfMemoryError(內存不足錯誤) |
運行時常量池 |
線程共享 |
屬於方法區的一部分。 存放編譯器生成的各種字面量和符號引用。 |
內存不足時,拋出OutOfMemoryError(內存不足錯誤) |