標籤:
類載入機制:
jvm把class檔案載入到記憶體,並對資料進行校正、解析和初始化,最終形成jvm可以直接使用的java類型的過程。
(1)載入
將class檔案位元組碼內容載入到記憶體中,並將這些待用資料轉換成方法區中的運行時資料結構,在堆中產生一個代表這個類的java.lang.Class對象,作為方法區類資料的訪問入口。
(2)連結 將java類的二進位代碼合并到jvm的運行狀態之中的過程
2.1 驗證
確保載入的類資訊符合jvm規範,沒有安全方面的問題。
2.2 準備
正式為類變數(static變數)分配記憶體並設定類變數初始值的階段,這些記憶體都將在方法區中進行分配。
2.3 解析
虛擬機器常量池內的符號引用替換為直接引用的過程。(比如String s ="aaa",轉化為 s的地址指向“aaa”的地址)
(3)初始化
初始化階段是執行類構造器方法的過程。類構造器方法是由編譯器自動收集類中的所有類變數的賦值動作和靜態語句塊(static塊)中的語句合并產生的。
當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先初始化其父類的初始化
虛擬機器會保證一個類的構造器方法在多線程環境中被正確加鎖和同步
當訪問一個java類的靜態域時,只有真正聲明這個靜態變數的類才會被初始化。
類載入過程分為:類的主動引用和類的被動引用
類的主動引用(一定會發生類的初始化)
--new一個類的對象
--調用類的靜態成員(除了final常量)和靜態方法
--使用java.lang.reflect包的方法對類進行反射調用
--當初始化一個類,如果其父類沒有被初始化,則先初始化他的父類
--當要執行某個程式時,一定先啟動main方法所在的類
類的被動引用(不會發生類的初始化)
--當訪問一個靜態變數時,只有真正生命這個靜態變數的類才會被初始化(通過子類引用父類的靜態變數,不會導致子類初始化)
--通過數組定義類應用,不會觸發此類的初始化 A[] a = new A[10];
--引用常量(final類型)不會觸發此類的初始化(常量在編譯階段就存入調用類的常量池中了)
類載入器的階層(樹狀結構)
引導類載入器(bootstrap class loader)
--他用類載入java 的核心庫(String 、Integer、List。。。)在jre/lib/rt.jar路徑下的內容,是用C代碼來實現的,並不繼承自java.lang.ClassLoader。
--載入擴充類和應用程式類載入器。並指定他們的父類載入器。
擴充類載入器(extensions class loader)
--用來載入java的擴充庫(jre/ext/*.jar路徑下的內容)java虛擬機器的實現會自動提供一個擴充目錄。該類載入器在此目錄裡面尋找並載入java類。
應用程式類載入器(application class loader)
--他根據java應用的類路徑(classpath路徑),一般來說,java應用的類都是由他來完成載入的
自訂類載入器
--開發人員可以通過繼承java.lang.ClassLoader類的方式實現自己的類載入器,以滿足一些特殊的需求。
擴充類載入器、應用程式類載入器、自訂類載入器均是由java實現,都繼承java.lang.ClassLoader類。
類載入器的代理模式:雙親委託機制
--就是某個特定的類載入器在接收到載入類的請求後,首先將載入任務委託給父類載入器,一次追溯,直到最高的爺爺輩的,如果父類載入器可以完成類載入任務,就成功返回;只要父類載入器無法完成次載入任務時,才自己載入。
--雙親機制是為了保證java核心庫的型別安全,不會出現使用者自己能定義java.lang.Object類的情況。
雙親委託機制是代理模式的一種,並不是所有的類載入器都採用雙親委託機制,tomcat伺服器類載入器也使用代理模式,所不同的是他是首先嘗試自己去載入某個類,如果找不到在代理給父類載入器。
java中類載入的全過程及記憶體配置圖分析