類的加載:
指的是將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.符號引用:
符號引用主要包括類和接口的完整類名,屬性的名稱和描述符,方法名和描述符等。
-----------------------------------------------------------