類的加載:
指的是将class檔案的二進制資料讀入到運作時資料區(JVM在記憶體中劃分的)
中,并在方法區内建立一個class對象。
類加載器:
負責加載編譯後的class檔案(位元組碼檔案)到JVM(Java虛拟機)當中。
而類加載器主要分為以下幾種:
1.Bootstrap class loader (引導類加載器)
負責加載Java核心類庫。在jre\lib目錄下,包括rt.jar(Java基礎類庫),這些
都是Java的核心類庫。而且這個加載器是由C語言編寫的,是以在Java程式中是擷取
不到的。
2.Extension class loader(擴充類加載器)
負責加載Java平台下擴充功能的jar包,這些jar包在jre\lib\ext目錄下。這個加載
器由Java語言編寫的。
3.System class loader(系統類加載器)
負責加載classpath目錄下的所有類庫,classpath目錄下的class檔案一般
是我們自己寫的java檔案編譯後的。而這個加載器是由Java語言寫的。
這些類加載器協同起來完成整個類的加載過程,是以這些類的加載模式基于
”雙親委托模型“。
”雙親委托模型“:
程式運作後,編譯器把Java檔案編譯成class檔案後,首先負責加載的是
系統類加載器,但它不會馬上加載,而是将此任務移送給它的父類加載器擴充
類加載器加載,擴充類加載器也是将此任務移送給引導類加載器加載。
class檔案到了引導類加載器那,它先判斷能不能加載這個類,如果能,就
加載;不能,移送給其子加載器,以此類推。最終我們編寫的class都會配置在
classpath環境中,是以,這個類加載任務還是由系統類加載器完成。如果系統
類加載器都不能加載,就抛出ClassNotFoundException。
當一個class加載到JVM中,類加載階段已經完成。接下來JVM配置設定記憶體,對整個
class檔案(檔案裡面都是二進制的彙編指令)進行内容解析(JVM對二進制的命
令逐行解析,交由CPU執行)。
記憶體配置設定:
JVM運作起來時就給記憶體劃分空間,這塊空間就稱為運作時資料區。
運作時資料區被劃分為以下幾塊内容:
1.棧:
每一個線程運作起來的時候就會對應一個棧(線程棧),棧中存放的資料被目前
線程所獨享(不會産生資源共享情況,是以線程是安全的)。而棧當中存放的是棧幀,
當線程調用方法時,就是形成一個棧幀,并将這個棧幀進行壓棧操作。方法執行完後,
進行出棧操作。這個棧幀裡面包括(局部變量,操作數棧,指向目前方法對應類的常
量池引用,方法傳回位址等資訊)。
2.本地方法棧:
本地方法棧的機制和棧的相似,差別在于,棧運作的是Java實作的方法,而本地
方法棧運作的是本地方法。本地方法指的是JVM需要調用非Java語言所實作的方法,
例如C語言。在JVM規範中,沒有強化性要求實作方一定要劃分出本地方法棧(例如:
HotSpot虛拟機将本地方法棧和棧合二為一)和具體實作(不同的作業系統,對JVM
規範的具體實作都不一樣)。
3.程式計數器:
程式計數器也可以稱為PC寄存器(通俗講就是 指令緩存)。它主要用于緩存目前
程式下一條指令的指令位址,CPU根據這個位址找到将要執行的指令。這個寄存器是JVM
内部實作的,不是實體概念上的計數器,不過和JVM的實作邏輯一樣。
4.堆:
堆記憶體主要存放建立的對象和數組。堆記憶體在JVM中是唯一的,能被多個線程所共享。
堆裡面的每一個對象都存放着執行個體的執行個體變量。堆記憶體的對象沒有被引用,會自動被Java
垃圾回收機制回收。
當在方法中定義了局部變量,如果這個變量是基本資料類型,那麼這個變量的值就直接
存放在棧中;如果這個變量是引用資料類型,那麼變量值就存放在堆記憶體中,而棧中存放的是
指向堆中的引用位址。
5.方法區:
方法區在JVM也是一個非常重要的一塊記憶體區域,和堆一樣,可以被多個線程多共享。
主要存放每一個加載class的資訊。class資訊主要包含魔數(确定是否是一個class檔案),常量
池,通路标志(目前的類是普通類還是接口,是否是抽象類,是否被public修飾,是否使用了final
修飾等描述資訊......),字段表集合資訊(使用什麼通路修飾符,是執行個體變量還是靜态變量,是否
使用了final修飾等描述資訊.....),方法表集合資訊(使用什麼通路修飾符,是否靜态方法,是否
使用了final修飾,是否使用了synchronized修飾,是否是native方法......)等内容。當一個類加
載器加載了一個類的時候,會根據這個class檔案建立一個class對象,class對象就包含了上述的資訊。
後續要建立這個類的執行個體,都根據這個class對象建立出來的。
6.常量池:
常量池是方法區中的一部分,存放class對象中最重要的資源。JVM為每一個class對象都維護一個
常量池。它主要存儲兩種類型的常量:
1.字面常量:
字面常量通常就是在Java中定義的字面量值。例如:int = 1,中的 1,String s = "hello",這個
hello就是字面量。或者使用final修飾的常量值。
2.符号引用:
符号引用主要包括類和接口的完整類名,屬性的名稱和描述符,方法名和描述符等。
-----------------------------------------------------------