JVM核心之JVM运行和类加载全过程
生活随笔
收集整理的這篇文章主要介紹了
JVM核心之JVM运行和类加载全过程
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
為什么研究類加載全過程?
- 有助于連接JVM運(yùn)行過程
- 更深入了解java動態(tài)性(解熱部署,動態(tài)加載),提高程序的靈活性
?
類加載機(jī)制
- JVM把class文件加載到內(nèi)存,并對數(shù)據(jù)進(jìn)行校驗(yàn)、解析和初始化,最終形成JVM可以直接使用的java類型的全過程。
?
?
?
- 加載
- 將class文件字節(jié)碼內(nèi)容加載到內(nèi)存中,并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)換成方法區(qū)中的運(yùn)行時數(shù)據(jù)結(jié)構(gòu),在堆中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)類數(shù)據(jù)的訪問入口,這個過程需要類加載器參與。
?
?
?
- 鏈接??? 將java類的二進(jìn)制代碼合并到JVM的運(yùn)行狀態(tài)之中的過程
- 驗(yàn)證:確保加載的類信息符合JVM規(guī)范,沒有安全方面的問題
-
- 準(zhǔn)備:正式為類變量(static變量)分配內(nèi)存并設(shè)置類變量初始值的階段,這些內(nèi)存都將在方法去中進(jìn)行分配
-
- 解析:虛擬機(jī)常量池的符號引用替換為字節(jié)引用過程
- 初始化
- 初始化階段是執(zhí)行類構(gòu)造器<clinit>()方法的過程。類構(gòu)造器<clinit>()方法是由編譯器自動收藏類中的所有類變量的賦值動作和靜態(tài)語句塊(static塊)中的語句合并產(chǎn)生
- 當(dāng)初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進(jìn)行過初始化,則需要先觸發(fā)其父類的初始化
- 虛擬機(jī)會保證一個類的<clinit>()方法在多線程環(huán)境中被正確加鎖和同步
- 當(dāng)范圍一個Java類的靜態(tài)域時,只有真正聲名這個域的類才會被初始化
?
?
例1:
?
public class Demo01 {public static void main(String[] args) {A a = new A();System.out.println(a.width);} }class A{public static int width=100; //靜態(tài)變量,靜態(tài)域 fieldstatic{System.out.println("靜態(tài)初始化類A");width = 300 ;}public A() {System.out.println("創(chuàng)建A類的對象");} }?
?
分析:
說明:
內(nèi)存中存在棧、堆(放創(chuàng)建好的對象)、方法區(qū)(實(shí)際也是一種特殊堆)
1、JVM加載Demo01時候,首先在方法區(qū)中形成Demo01類對應(yīng)靜態(tài)數(shù)據(jù)(類變量、類方法、代碼…),同時在堆里面也會形成java.lang.Class對象(反射對象),代表Demo01類,通過對象可以訪問到類二進(jìn)制結(jié)構(gòu)。然后加載變量A類信息,同時也會在堆里面形成a對象,代表A類。
2、main方法執(zhí)行時會在棧里面形成main方法棧幀,一個方法對應(yīng)一個棧幀。如果main方法調(diào)用了別的方法,會在棧里面挨個往里壓,main方法里面有個局部變量A類型的a,一開始a值為null,通過new調(diào)用類A的構(gòu)造器,棧里面生成A()方法同時堆里面生成A對象,然后把A對象地址付給棧中的a,此時a擁有A對象地址。
3、當(dāng)調(diào)用A.width時,調(diào)用方法區(qū)數(shù)據(jù)。
?
當(dāng)類被引用的加載,類只會加載一次
- 類的主動引用(一定會發(fā)生類的初始化)
- new一個類的對象
- 調(diào)用類的靜態(tài)成員(除了final常量)和靜態(tài)方法
- 使用java.lang.reflect包的方法對類進(jìn)行反射調(diào)用
- 當(dāng)虛擬機(jī)啟動,java Demo01,則一定會初始化Demo01類,說白了就是先啟動main方法所在的類
- 當(dāng)初始化一個類,如果其父類沒有被初始化,則先初始化它父類
- 類的被動引用(不會發(fā)生類的初始化)
- 當(dāng)訪問一個靜態(tài)域時,只有真正聲名這個域的類才會被初始化
- 通過子類引用父類的靜態(tài)變量,不會導(dǎo)致子類初始化
- 通過數(shù)組定義類的引用,不會觸發(fā)此類初始化
- 引用常量不會觸發(fā)此類的初始化(常量在編譯階段就存入調(diào)用類的常量池中了)
- 當(dāng)訪問一個靜態(tài)域時,只有真正聲名這個域的類才會被初始化
例2:
?
public class Demo01 {static{System.out.println("靜態(tài)初始化Demo01");}public static void main(String[] args) throws Exception {System.out.println("Demo01的main方法!");System.out.println(System.getProperty("java.class.path"));//主動引用 // new A(); // System.out.println(A.width); // Class.forName("com.sinosoft.test.A");//被動引用 // System.out.println(A.MAX); // A[] as = new A[10];System.out.println(B.width);//B類不會被加載} }class B extends A {static {System.out.println("靜態(tài)初始化B");} }class A extends A_Father {public static int width=100; //靜態(tài)變量,靜態(tài)域 fieldpublic static final int MAX=100; static {System.out.println("靜態(tài)初始化類A");width=300;}public A(){System.out.println("創(chuàng)建A類的對象");} }class A_Father extends Object {static {System.out.println("靜態(tài)初始化A_Father");} }?
?
總結(jié)
以上是生活随笔為你收集整理的JVM核心之JVM运行和类加载全过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 密度仅提升10% 台积电2nm工艺挤牙膏
- 下一篇: 圆满了!曝小米三大新旗舰全系上12+51