【JVM】类的生命周期【转+整理】
參考如下三篇并整理。
1.Java類加載機(jī)制詳解
2.深入理解Java:類加載機(jī)制及反射
3.jvm系列(一):java類的加載機(jī)制
?
?
類的生命周期是從被加載到虛擬機(jī)內(nèi)存中開始,到卸載出內(nèi)存結(jié)束。過程共有七個(gè)階段。
1.加載---2.驗(yàn)證---3.準(zhǔn)備---3.解析---5.初始化---6.使用---7.卸載
|________連接________|
|______________類的加載過程_____________|
|______________________類的生命周期_______________________|
?
其中類加載的過程包括了加載、驗(yàn)證、準(zhǔn)備、解析、初始化五個(gè)階段。
在這五個(gè)階段中,加載、驗(yàn)證、準(zhǔn)備和初始化這四個(gè)階段發(fā)生的順序是確定的,而解析階段則不一定,它在某些情況下可以在初始化階段之后開始,這是為了支持Java語言的運(yùn)行時(shí)綁定(也成為動(dòng)態(tài)綁定或晚期綁定)。
另外注意這里的幾個(gè)階段是按順序開始,而不是按順序進(jìn)行或完成,因?yàn)檫@些階段通常都是互相交叉地混合進(jìn)行的,通常在一個(gè)階段執(zhí)行的過程中調(diào)用或激活另一個(gè)階段。
?
【1.加載(裝載)】
在裝載階段,虛擬機(jī)需要完成以下3件事情
(1) 通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。
(2) 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
(3) 在Java堆中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為方法區(qū)這些數(shù)據(jù)的訪問入口。
虛擬機(jī)規(guī)范中并沒有準(zhǔn)確說明二進(jìn)制字節(jié)流應(yīng)該從哪里獲取以及怎樣獲取,這里可以通過定義自己的類加載器去控制字節(jié)流的獲取方式。
?
這里第1條中的二進(jìn)制字節(jié)流并不只是單純地從Class文件中獲取,比如它還可以從Jar包中獲取、從網(wǎng)絡(luò)中獲取(最典型的應(yīng)用便Applet)、由其他文件生成(JSP應(yīng)用)等。
相對(duì)于類加載的其他階段而言,加載階段(準(zhǔn)確地說,是加載階段獲取類的二進(jìn)制字節(jié)流的動(dòng)作)是可控性最強(qiáng)的階段,因?yàn)殚_發(fā)人員既以使用系統(tǒng)提供的類加載器來完成加載,也可以自定義自己的類加載器來完成加載。
?
?
【2.驗(yàn)證(校驗(yàn)、檢查)】
虛擬機(jī)如果不檢查輸入的字節(jié)流,對(duì)其完全信任的話,很可能會(huì)因?yàn)檩d入了有害的字節(jié)流而導(dǎo)致系統(tǒng)奔潰。
?
1.文件格式驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范;例如:是否以0xCAFEBABE開頭、主次版本號(hào)是否在當(dāng)前虛擬機(jī)的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類型。
2.元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語義分析(注意:對(duì)比javac編譯階段的語義分析),以保證其描述的信息符合Java語言規(guī)范的要求;例如:這個(gè)類是否有父類,除了java.lang.Object之外。
3.字節(jié)碼驗(yàn)證:通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的、符合邏輯的。
4.符號(hào)引用驗(yàn)證:確保解析動(dòng)作能正確執(zhí)行。
驗(yàn)證階段是非常重要的,但不是必須的,它對(duì)程序運(yùn)行期沒有影響,如果所引用的類經(jīng)過反復(fù)驗(yàn)證,
那么可以考慮采用-Xverifynone參數(shù)來關(guān)閉大部分的類驗(yàn)證措施,以縮短虛擬機(jī)類加載的時(shí)間。
?
【3.準(zhǔn)備】————為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值
這個(gè)階段正式為類變量(被static修飾的變量)分配內(nèi)存并設(shè)置類變量初始值,這個(gè)內(nèi)存分配是發(fā)生在方法區(qū)中。
1、注意這里并沒有對(duì)實(shí)例變量進(jìn)行內(nèi)存分配,實(shí)例變量將會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一起分配在JAVA堆中。
2、這里設(shè)置的初始值,通常是指數(shù)據(jù)類型的‘“零”值。
public?static?int?value?=?123;
value在準(zhǔn)備階段過后的初始值為0而不是123,而把value賦值的putstatic指令將在初始化階段才會(huì)被執(zhí)行。
注意:
(1)對(duì)基本數(shù)據(jù)類型來說,對(duì)于類變量(static)和全局變量,如果不顯式地對(duì)其賦值而直接使用,則系統(tǒng)會(huì)為其賦予默認(rèn)的零值。
(2)對(duì)基本數(shù)據(jù)類型來說,對(duì)于局部變量來說,在使用前必須顯式地為其賦值,否則編譯時(shí)不通過。
(3)對(duì)于同時(shí)被static和final修飾的常量,必須在聲明的時(shí)候就為其顯式地賦值,否則編譯時(shí)不通過;
(4)只被final修飾的常量則既可以在聲明時(shí)顯式地賦值,也可以在類初始化時(shí)顯式地為其賦值,總之,在使用前必須為其顯式地賦值,系統(tǒng)不會(huì)為其賦予默認(rèn)零值。
(5)對(duì)于引用數(shù)據(jù)類型reference來說,如數(shù)組引用、對(duì)象引用等,如果沒有對(duì)其進(jìn)行顯式地賦值而直接使用,系統(tǒng)都會(huì)為其賦予默認(rèn)的零值,即null。
(6)如果在數(shù)組初始化時(shí)沒有對(duì)數(shù)組中的各元素賦值,那么其中的元素將根據(jù)對(duì)應(yīng)的數(shù)據(jù)類型而被賦予默認(rèn)的零值。
3、static final常量在準(zhǔn)備階段變量value就會(huì)被初始化為ConstValue屬性所指定的值,將其結(jié)果放入了調(diào)用它的類的常量池中。
public static final int value = 3;
編譯時(shí)Javac將會(huì)為value生成ConstantValue屬性,在準(zhǔn)備階段虛擬機(jī)就會(huì)根據(jù)ConstantValue的設(shè)置將value賦值為3。
?
下表列出了Java中所有基本數(shù)據(jù)類型以及reference類型的默認(rèn)零值:
?
?
?
【4.解析】————把類中的符號(hào)引用轉(zhuǎn)換為直接引用
?
解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過程,解析動(dòng)作主要針對(duì)類或接口、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用點(diǎn)限定符7類符號(hào)引用進(jìn)行。
符號(hào)引用就是一組符號(hào)來描述目標(biāo),可以是任何字面量。
?
直接引用就是直接指向目標(biāo)的指針、相對(duì)偏移量或一個(gè)間接定位到目標(biāo)的句柄。
?
? 1、類或接口的解析:判斷所要轉(zhuǎn)化成的直接引用是對(duì)數(shù)組類型,還是普通的對(duì)象類型的引用,從而進(jìn)行不同的解析。 ? ??2、字段解析:對(duì)字段進(jìn)行解析時(shí),會(huì)先在本類中查找是否包含有簡單名稱和字段描述符都與目標(biāo)相匹配的字段,如果有,則查找結(jié)束; 如果沒有,則會(huì)按照繼承關(guān)系從上往下遞歸搜索該類所實(shí)現(xiàn)的各個(gè)接口和它們的父接口,還沒有,則按照繼承關(guān)系從上往下遞歸搜索其父類,直至查找結(jié)束,查找流程如下圖所示: 3、類方法解析:對(duì)類方法的解析與對(duì)字段解析的搜索步驟差不多,只是多了判斷該方法所處的是類還是接口的步驟,而且對(duì)類方法的匹配搜索,是先搜索父類,再搜索接口。 ? ?? 4、接口方法解析:與類方法解析步驟類似,知識(shí)接口不會(huì)有父類,因此,只遞歸向上搜索父接口就行了。?
【5.初始化】
詳細(xì)見此
?類初始化時(shí)機(jī):只有當(dāng)對(duì)類的主動(dòng)使用的時(shí)候才會(huì)導(dǎo)致類的初始化,類的主動(dòng)使用包括以下(四大種)六小種:
【1】在如下三個(gè)場(chǎng)景(能生成四個(gè)字節(jié)碼指令的場(chǎng)景),如果類還未初始化,則初始化。
(4個(gè)指令【new、getstatic、putstatic、invokestatic】)
A.new
new Test();B.讀取或設(shè)置類的靜態(tài)變量
int b=Test.a;Test.a=b;C.調(diào)用靜態(tài)函數(shù)
Test.doSomething();【2】反射調(diào)用。
Class.forName(“com.mengdd.Test”);【3】子類初始化,要先初始化父類(所有父類)。
【4】虛擬機(jī)啟動(dòng)時(shí),要初始化主類。直接使用java.exe命令來運(yùn)行某個(gè)主類。
?
只有上述四種情況會(huì)觸發(fā)初始化,也稱為對(duì)一個(gè)類進(jìn)行主動(dòng)引用。
除此以外,有其他方式都不會(huì)觸發(fā)初始化,稱為被動(dòng)引用。
注意:
(1)子類引用父類的靜態(tài)變量,不會(huì)導(dǎo)致子類初始化。
(2)通過數(shù)組定義引用類,不會(huì)觸發(fā)此類的初始化
(3)引用常量時(shí),不會(huì)觸發(fā)該類的初始化
舉例:
(1)子類引用父類的靜態(tài)變量,不會(huì)導(dǎo)致子類初始化。
public class SupClass {public static int a = 123;static{System.out.println("supclass init");} }public class SubClass extends SupClass {static{System.out.println("subclass init");} }public class Test {public static void main(String[] args){System.out.println(SubClass.a);} }執(zhí)行結(jié)果:
supclass init 123(2)通過數(shù)組定義引用類,不會(huì)觸發(fā)此類的初始化
public class SupClass {public static int a = 123;static{System.out.println("supclass init");} }public class Test {public static void main(String[] args){SupClass[] spc = new SupClass[10];} }執(zhí)行結(jié)果:
?(3)引用常量時(shí),不會(huì)觸發(fā)該類的初始化
public class ConstClass {public static final String A= "MIGU";static{System.out.println("ConstCLass init");} }public class TestMain {public static void main(String[] args){System.out.println(ConstClass.A);} }執(zhí)行結(jié)果:
MIGU用final修飾某個(gè)類變量時(shí),它的值在編譯時(shí)就已經(jīng)確定好放入常量池了,所以在訪問該類變量時(shí),等于直接從常量池中獲取,并沒有初始化該類。
初始化的步驟
1、如果該類還沒有加載和連接,則程序先加載該類并連接。
2、如果該類的直接父類沒有加載,則先初始化其直接父類。
3、如果類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句。
在第二個(gè)步驟中,如果直接父類又有直接父類,則系統(tǒng)會(huì)再次重復(fù)這三個(gè)步驟來初始化這個(gè)父類,
依次類推,JVM最先初始化的總是java.lang.Object類。
當(dāng)程序主動(dòng)使用任何一個(gè)類時(shí),系統(tǒng)會(huì)保證該類以及所有的父類都會(huì)被初始化。
【6.使用】
?
【7.卸載】
?
在如下幾種情況下,Java虛擬機(jī)將結(jié)束生命周期
1.執(zhí)行了System.exit()方法
2.程序正常執(zhí)行結(jié)束
3.程序在執(zhí)行過程中遇到了異常或錯(cuò)誤而異常終止
4.由于操作系統(tǒng)出現(xiàn)錯(cuò)誤而導(dǎo)致Java虛擬機(jī)進(jìn)程終止
?
轉(zhuǎn)載于:https://www.cnblogs.com/CESC4/p/8037858.html
總結(jié)
以上是生活随笔為你收集整理的【JVM】类的生命周期【转+整理】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php实现 字符串加密(分类分布分工,
- 下一篇: 斯坦福-随机图模型-week4.0_