日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

【JVM】类的生命周期【转+整理】

發(fā)布時(shí)間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【JVM】类的生命周期【转+整理】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

參考如下三篇并整理。

1.Java類(lèi)加載機(jī)制詳解

2.深入理解Java:類(lèi)加載機(jī)制及反射

3.jvm系列(一):java類(lèi)的加載機(jī)制

?

?

類(lèi)的生命周期是從被加載到虛擬機(jī)內(nèi)存中開(kāi)始,到卸載出內(nèi)存結(jié)束。過(guò)程共有七個(gè)階段。

1.加載---2.驗(yàn)證---3.準(zhǔn)備---3.解析---5.初始化---6.使用---7.卸載

     |________連接________| 

|______________類(lèi)的加載過(guò)程_____________|

|______________________類(lèi)的生命周期_______________________|

?

其中類(lèi)加載的過(guò)程包括了加載、驗(yàn)證、準(zhǔn)備、解析、初始化五個(gè)階段。

在這五個(gè)階段中,加載、驗(yàn)證、準(zhǔn)備和初始化這四個(gè)階段發(fā)生的順序是確定的,而解析階段則不一定,它在某些情況下可以在初始化階段之后開(kāi)始,這是為了支持Java語(yǔ)言的運(yùn)行時(shí)綁定(也成為動(dòng)態(tài)綁定或晚期綁定)。

另外注意這里的幾個(gè)階段是按順序開(kāi)始,而不是按順序進(jìn)行或完成,因?yàn)檫@些階段通常都是互相交叉地混合進(jìn)行的,通常在一個(gè)階段執(zhí)行的過(guò)程中調(diào)用或激活另一個(gè)階段。


?

【1.加載(裝載)】

在裝載階段,虛擬機(jī)需要完成以下3件事情
(1) 通過(guò)一個(gè)類(lèi)的全限定名來(lái)獲取定義此類(lèi)的二進(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è)類(lèi)的java.lang.Class對(duì)象,作為方法區(qū)這些數(shù)據(jù)的訪問(wèn)入口。
虛擬機(jī)規(guī)范中并沒(méi)有準(zhǔn)確說(shuō)明二進(jìn)制字節(jié)流應(yīng)該從哪里獲取以及怎樣獲取,這里可以通過(guò)定義自己的類(lèi)加載器去控制字節(jié)流的獲取方式。

?

這里第1條中的二進(jìn)制字節(jié)流并不只是單純地從Class文件中獲取,比如它還可以從Jar包中獲取、從網(wǎng)絡(luò)中獲取(最典型的應(yīng)用便Applet)、由其他文件生成(JSP應(yīng)用)等。

相對(duì)于類(lèi)加載的其他階段而言,加載階段(準(zhǔn)確地說(shuō),是加載階段獲取類(lèi)的二進(jìn)制字節(jié)流的動(dòng)作)是可控性最強(qiáng)的階段,因?yàn)殚_(kāi)發(fā)人員既以使用系統(tǒng)提供的類(lèi)加載器來(lái)完成加載,也可以自定義自己的類(lèi)加載器來(lái)完成加載。

?

?

【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開(kāi)頭、主次版本號(hào)是否在當(dāng)前虛擬機(jī)的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類(lèi)型。
  2.元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析(注意:對(duì)比javac編譯階段的語(yǔ)義分析),以保證其描述的信息符合Java語(yǔ)言規(guī)范的要求;例如:這個(gè)類(lèi)是否有父類(lèi),除了java.lang.Object之外。
  3.字節(jié)碼驗(yàn)證:通過(guò)數(shù)據(jù)流和控制流分析,確定程序語(yǔ)義是合法的、符合邏輯的。
  4.符號(hào)引用驗(yàn)證:確保解析動(dòng)作能正確執(zhí)行。
  驗(yàn)證階段是非常重要的,但不是必須的,它對(duì)程序運(yùn)行期沒(méi)有影響,如果所引用的類(lèi)經(jīng)過(guò)反復(fù)驗(yàn)證,

  那么可以考慮采用-Xverifynone參數(shù)來(lái)關(guān)閉大部分的類(lèi)驗(yàn)證措施,以縮短虛擬機(jī)類(lèi)加載的時(shí)間。

?

【3.準(zhǔn)備】————為類(lèi)的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值

這個(gè)階段正式為類(lèi)變量(被static修飾的變量)分配內(nèi)存并設(shè)置類(lèi)變量初始值,這個(gè)內(nèi)存分配是發(fā)生在方法區(qū)中。

1、注意這里并沒(méi)有對(duì)實(shí)例變量進(jìn)行內(nèi)存分配,實(shí)例變量將會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一起分配在JAVA堆中。

2、這里設(shè)置的初始值,通常是指數(shù)據(jù)類(lèi)型的‘“零”值。

  public?static?int?value?=?123;

  value在準(zhǔn)備階段過(guò)后的初始值為0而不是123,而把value賦值的putstatic指令將在初始化階段才會(huì)被執(zhí)行。

  注意:

  (1)對(duì)基本數(shù)據(jù)類(lèi)型來(lái)說(shuō),對(duì)于類(lèi)變量(static)和全局變量,如果不顯式地對(duì)其賦值而直接使用,則系統(tǒng)會(huì)為其賦予默認(rèn)的零值。

  (2)對(duì)基本數(shù)據(jù)類(lèi)型來(lái)說(shuō),對(duì)于局部變量來(lái)說(shuō),在使用前必須顯式地為其賦值,否則編譯時(shí)不通過(guò)。

  (3)對(duì)于同時(shí)被static和final修飾的常量,必須在聲明的時(shí)候就為其顯式地賦值,否則編譯時(shí)不通過(guò);

  (4)只被final修飾的常量則既可以在聲明時(shí)顯式地賦值,也可以在類(lèi)初始化時(shí)顯式地為其賦值,總之,在使用前必須為其顯式地賦值,系統(tǒng)不會(huì)為其賦予默認(rèn)零值。

  (5)對(duì)于引用數(shù)據(jù)類(lèi)型reference來(lái)說(shuō),如數(shù)組引用、對(duì)象引用等,如果沒(méi)有對(duì)其進(jìn)行顯式地賦值而直接使用,系統(tǒng)都會(huì)為其賦予默認(rèn)的零值,即null。

  (6)如果在數(shù)組初始化時(shí)沒(méi)有對(duì)數(shù)組中的各元素賦值,那么其中的元素將根據(jù)對(duì)應(yīng)的數(shù)據(jù)類(lèi)型而被賦予默認(rèn)的零值。

3、static final常量在準(zhǔn)備階段變量value就會(huì)被初始化為ConstValue屬性所指定的值,將其結(jié)果放入了調(diào)用它的類(lèi)的常量池中。

  public static final int value = 3;

  編譯時(shí)Javac將會(huì)為value生成ConstantValue屬性,在準(zhǔn)備階段虛擬機(jī)就會(huì)根據(jù)ConstantValue的設(shè)置將value賦值為3。

?

下表列出了Java中所有基本數(shù)據(jù)類(lèi)型以及reference類(lèi)型的默認(rèn)零值:

?

?

?

【4.解析】————把類(lèi)中的符號(hào)引用轉(zhuǎn)換為直接引用

?

  解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程,解析動(dòng)作主要針對(duì)類(lèi)或接口、字段、類(lèi)方法、接口方法、方法類(lèi)型、方法句柄和調(diào)用點(diǎn)限定符7類(lèi)符號(hào)引用進(jìn)行。

  符號(hào)引用就是一組符號(hào)來(lái)描述目標(biāo),可以是任何字面量。

?

  直接引用就是直接指向目標(biāo)的指針、相對(duì)偏移量或一個(gè)間接定位到目標(biāo)的句柄。

?

?  1、類(lèi)或接口的解析:判斷所要轉(zhuǎn)化成的直接引用是對(duì)數(shù)組類(lèi)型,還是普通的對(duì)象類(lèi)型的引用,從而進(jìn)行不同的解析。 ? ??2、字段解析:對(duì)字段進(jìn)行解析時(shí),會(huì)先在本類(lèi)中查找是否包含有簡(jiǎn)單名稱(chēng)和字段描述符都與目標(biāo)相匹配的字段,如果有,則查找結(jié)束; 如果沒(méi)有,則會(huì)按照繼承關(guān)系從上往下遞歸搜索該類(lèi)所實(shí)現(xiàn)的各個(gè)接口和它們的父接口,還沒(méi)有,則按照繼承關(guān)系從上往下遞歸搜索其父類(lèi),直至查找結(jié)束,查找流程如下圖所示:   3、類(lèi)方法解析:對(duì)類(lèi)方法的解析與對(duì)字段解析的搜索步驟差不多,只是多了判斷該方法所處的是類(lèi)還是接口的步驟,而且對(duì)類(lèi)方法的匹配搜索,是先搜索父類(lèi),再搜索接口。 ? ?? 4、接口方法解析:與類(lèi)方法解析步驟類(lèi)似,知識(shí)接口不會(huì)有父類(lèi),因此,只遞歸向上搜索父接口就行了。

?

【5.初始化】

  詳細(xì)見(jiàn)此

  ?類(lèi)初始化時(shí)機(jī):只有當(dāng)對(duì)類(lèi)的主動(dòng)使用的時(shí)候才會(huì)導(dǎo)致類(lèi)的初始化,類(lèi)的主動(dòng)使用包括以下(四大種)六小種:

  【1】在如下三個(gè)場(chǎng)景(能生成四個(gè)字節(jié)碼指令的場(chǎng)景),如果類(lèi)還未初始化,則初始化。

        (4個(gè)指令【new、getstatic、putstatic、invokestatic】)

   A.new

      new Test();

   B.讀取或設(shè)置類(lèi)的靜態(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】子類(lèi)初始化,要先初始化父類(lèi)(所有父類(lèi))。

  【4】虛擬機(jī)啟動(dòng)時(shí),要初始化主類(lèi)。直接使用java.exe命令來(lái)運(yùn)行某個(gè)主類(lèi)。

?

   只有上述四種情況會(huì)觸發(fā)初始化,也稱(chēng)為對(duì)一個(gè)類(lèi)進(jìn)行主動(dòng)引用。

   除此以外,有其他方式都不會(huì)觸發(fā)初始化,稱(chēng)為被動(dòng)引用。

注意:

(1)子類(lèi)引用父類(lèi)的靜態(tài)變量,不會(huì)導(dǎo)致子類(lèi)初始化。

(2)通過(guò)數(shù)組定義引用類(lèi),不會(huì)觸發(fā)此類(lèi)的初始化

(3)引用常量時(shí),不會(huì)觸發(fā)該類(lèi)的初始化

舉例:

(1)子類(lèi)引用父類(lèi)的靜態(tài)變量,不會(huì)導(dǎo)致子類(lèi)初始化。

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)通過(guò)數(shù)組定義引用類(lèi),不會(huì)觸發(fā)此類(lèi)的初始化

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ā)該類(lèi)的初始化

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è)類(lèi)變量時(shí),它的值在編譯時(shí)就已經(jīng)確定好放入常量池了,所以在訪問(wèn)該類(lèi)變量時(shí),等于直接從常量池中獲取,并沒(méi)有初始化該類(lèi)。

初始化的步驟

1、如果該類(lèi)還沒(méi)有加載和連接,則程序先加載該類(lèi)并連接。

2、如果該類(lèi)的直接父類(lèi)沒(méi)有加載,則先初始化其直接父類(lèi)。

3、如果類(lèi)中有初始化語(yǔ)句,則系統(tǒng)依次執(zhí)行這些初始化語(yǔ)句。

在第二個(gè)步驟中,如果直接父類(lèi)又有直接父類(lèi),則系統(tǒng)會(huì)再次重復(fù)這三個(gè)步驟來(lái)初始化這個(gè)父類(lèi),

依次類(lèi)推,JVM最先初始化的總是java.lang.Object類(lèi)。

當(dāng)程序主動(dòng)使用任何一個(gè)類(lèi)時(shí),系統(tǒng)會(huì)保證該類(lèi)以及所有的父類(lèi)都會(huì)被初始化。

【6.使用】

?

【7.卸載】

?

  在如下幾種情況下,Java虛擬機(jī)將結(jié)束生命周期

  1.執(zhí)行了System.exit()方法

  2.程序正常執(zhí)行結(jié)束

  3.程序在執(zhí)行過(guò)程中遇到了異常或錯(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】类的生命周期【转+整理】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。