成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

虛擬機類加載機制

k00baa / 836人閱讀

摘要:加載階段在類的加載階段,虛擬機需要完成以下件事情通過一個類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。驗證階段驗證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求,并且不會危害虛擬機自身的安全。

注:本篇文章中的內(nèi)容是根據(jù)《深入理解Java虛擬機--JVM高級特性與最佳實踐》而總結(jié)的,如有理解錯誤,歡迎大家指正!

虛擬機把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對數(shù)據(jù)進(jìn)行校驗、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機之間使用的Java類型,這就是虛擬機的類加載機制。

類的生命周期

類從被加載到虛擬機內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個生命周期包括:加載、驗證、準(zhǔn)備、解析、初始化、使用、卸載7個階段,其中驗證、準(zhǔn)備、解析3個部分被稱為接連。

什么時候需要對類進(jìn)行初始化

什么情況下需要對類進(jìn)行加載,Java虛擬機規(guī)范中并沒有進(jìn)行強制約束,但虛擬機規(guī)范中卻嚴(yán)格規(guī)定類有且只有5中情況必須立即對類進(jìn)行初始化(而加載、驗證等自然而然需要在此之前開始)。

遇到new、getstatic、putstatic、invokestatic這四條字節(jié)碼指令時,如果類沒有進(jìn)行過初始化,則需要先出發(fā)其初始化。這四條指令最常見的場景是:使用new關(guān)鍵字實例化對象的時候、讀取或者設(shè)置一個類的靜態(tài)字段的時候、以及調(diào)用一個類的靜態(tài)方法的時候。

使用java.lang.reflect包的方法對類進(jìn)行反射調(diào)用的時候,如果類沒有進(jìn)行過初始化,則需要先觸發(fā)其初始化。

當(dāng)初始化一個類的時候,如果發(fā)現(xiàn)其父類還沒有進(jìn)行過初始化,則需要先觸發(fā)其父類的初始化。

當(dāng)虛擬機啟動時,用戶需要指定一個要執(zhí)行的主類(包含main()方法的那個類),虛擬機會先初始化這個主類。

當(dāng)使用JDK1.7的動態(tài)語言支持時,如果一個java.lang.invoke.MethodHandle實例最后的解析結(jié)果是REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄并且這個方法句柄所對應(yīng)的類還沒有進(jìn)行初始化,則需要先觸發(fā)其初始化。

加載階段

在類的加載階段,虛擬機需要完成以下3件事情:

通過一個類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流。

將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。

在內(nèi)存中生成一個代表這個類的java.lang.Class對象,作為方法區(qū)這個類的各種數(shù)據(jù)的訪問接口。

驗證階段

驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求,并且不會危害虛擬機自身的安全。驗證階段大致上會完成下面4個階段的檢查動作:

文件格式驗證
主要是語法校驗,例如是否以魔數(shù)0xCAFEBASE開頭、常量池中是否有不被支持的常量類型等。

元數(shù)據(jù)驗證
對類的元數(shù)據(jù)進(jìn)行語義校驗,保證不存在不符合Java語言規(guī)范的元數(shù)據(jù)信息。例如這個類是否有父類、這個父類是否繼承了不允許被繼承的類、如果這個類不是抽象類,是否實現(xiàn)了其父類或者接口之中要求實現(xiàn)的所有方法等。

字節(jié)碼驗證
通過數(shù)據(jù)流和控制流分析,確定程序語義是否合法。例如保證指令不會跳轉(zhuǎn)到方法體以外的字節(jié)碼指令上、保證方法體中的類型轉(zhuǎn)換是有效的等。

符號引用驗證
確保解析動作能夠正常執(zhí)行。例如引用中通過字符串描述的全限定名是否能夠找到對應(yīng)的類、符號引用中的類、字段、方法的訪問性(private、protected、public、default)是否可被當(dāng)前類訪問等。

準(zhǔn)備階段

準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些變量所使用的內(nèi)存都將在方法區(qū)中進(jìn)行分配。有兩點需要注意:首先,這個時候進(jìn)行內(nèi)存分配的僅包含類變量(被static修飾的變量),而不包含實例變量,實例變量將會在對象實例化時隨著對象一起分配在Java堆上中;其次,這里所說的初始值通常情況下時數(shù)據(jù)類型的零值。例如

public static int value = 1;

那變量value在準(zhǔn)備階段過后的初始值為0,而不是1。在初始化階段,才會把1賦值給value。

解析階段

解析階段是虛擬機將常量池內(nèi)的符號引用替換為直接引用的過程。符號引用以一組符號來描述所引用的目標(biāo),它和虛擬機的內(nèi)存布局無關(guān);直接引用可以是直接指向目標(biāo)的指針、相對偏移量或者一個能間接定位到目標(biāo)的句柄。直接引用是和虛擬機實現(xiàn)的內(nèi)存布局有關(guān)。

初始化階段

初始化階段是類加載過程的最后一步。在準(zhǔn)備階段,類變量已經(jīng)賦過一次系統(tǒng)要求的初始值,而在初始化階段,則根據(jù)程序員通過程序定制的主觀計劃去初始化類變量和其他資源,或者可以從另外一個角度表達(dá):初始化階段是執(zhí)行類構(gòu)造器()方法的過程。

()方法是由編譯器自動收集類中的所有變量的賦值動作和靜態(tài)語句塊中的語句合并產(chǎn)生的,編譯器收集的順序是由語句在源文件中出現(xiàn)的順序所決定的,靜態(tài)語句塊中只能訪問到定義在靜態(tài)語句塊之前的類變量,定義在它之后的類變量,在靜態(tài)語句塊中可以賦值,但不可以訪問。

()方法與實例構(gòu)造器()方法不同,它不需要顯示的調(diào)用父類構(gòu)造器,虛擬機會保證在子類的()方法執(zhí)行之前,父類的()方法已經(jīng)執(zhí)行完畢,因此在虛擬機中,第一個被執(zhí)行的()方法肯定是java.lang.Object。

由于父類的()方法先執(zhí)行,也就意味著父類中定義的靜態(tài)語句塊要優(yōu)先于子類的類變量賦值操作。

()方法對于類或者接口來說并不是必需的,如果一個類中沒有靜態(tài)語句塊,也沒有對類變量的賦值操作,那么編譯器就不會為這個類生成()方法。

接口中不能有靜態(tài)語句塊,但可以有類變量的賦值操作,因此接口和類都會生出()方法,但執(zhí)行接口中的()方法不需要先執(zhí)行父類的()方法,只有當(dāng)子接口使用類父接口的 變量時,父接口才會初始化,另外,接口的實現(xiàn)類也不需要在初始化的時候執(zhí)行接口的()方法。

虛擬機會保證一個類的()方法在多線程環(huán)境中被正確的加鎖、同步,如果多個線程同時去初始化一個類,那么只有一個線程去執(zhí)行這個類的()方法,其他線程阻塞等待。

類加載器

類加載器除了用于實現(xiàn)類的加載動作外,還起到了命名空間的作用。對于任何一個類來說,都需要有加載它的類加載器和這個類本身一同確立其在Java虛擬機中的唯一性,每一個類加載器,都擁有一個獨立的類名稱空間。

類加載器的雙親委派模型

啟動類加載器:它使用C++語言實現(xiàn),主要負(fù)責(zé)將存放在lib目錄下的類庫加載到虛擬機內(nèi)存中。

擴展類加載器:它使用Java語言實現(xiàn),主要負(fù)責(zé)加載libext目錄下的類庫。

應(yīng)用程序類加載器:它使用Java語言實現(xiàn),它負(fù)責(zé)加載用戶類路徑上所指定的類庫。如果應(yīng)用程序中沒有自定義類加載器,一般情況下,這個就是程序中默認(rèn)的類加載器。

自定義類加載器:開發(fā)者自定義的類加載器。

雙親委派模型要求除了頂層的啟動類加載器之外,其余的類加載器都應(yīng)當(dāng)有父類加載器。這里的父子關(guān)系不是以繼承來實現(xiàn)的,而是用組合的方式來實現(xiàn)。雙親委派模型的工作過程為:如果一個類加載器收到了類加載的請求,它首先不會自己嘗試加載該類,而是把這個請求委派給父類加載器去完成,每個層次的類加載器都是如此,因此所有的加載請求最終都會被傳送到啟動類加載器中,只有當(dāng)父類加載器反饋自己無法完成這個加載請求時,子加載器才會嘗試自己去加載。

使用雙親委派模型的好處就是Java類隨著它的加載器一起具備類一種帶有優(yōu)先級的層次關(guān)系。例如類java.lang.object,它存放在rt.jar中,無論哪個類加載器要加載這個類,最終都委派給最頂層的啟動類加載器進(jìn)行加載,因此Object類在程序的各種類加載器環(huán)境中都是同一個類。相反,如果沒有雙親委派模型,由各個類加載器自行去加載的話,如果用戶自己編寫了一個java.lang.Object的類,并放在程序的ClassPath中,那系統(tǒng)中將會出現(xiàn)多個不同的Object類,Java類型體系中最基礎(chǔ)的行為也就無法保證。應(yīng)用程序也將變得一片混亂。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76969.html

相關(guān)文章

  • 虛擬機類加載機制(讀書筆記)

    摘要:類從被加載到虛擬機內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個生命周期包括加載驗證準(zhǔn)備解析初始化使用和卸載 類從被加載到虛擬機內(nèi)存中開始,到卸載出內(nèi)存為止,它的整個生命周期包括:加載(Loading)、驗證(verification)、準(zhǔn)備(preparation)、解析(resolution)、初始化(initialization)、使用(using)和卸載(unloading)

    stormjun 評論0 收藏0
  • JAVA 虛擬機類加載機制和字節(jié)碼執(zhí)行引擎

    摘要:實現(xiàn)這個口號的就是可以運行在不同平臺上的虛擬機和與平臺無關(guān)的字節(jié)碼。類加載過程加載加載是類加載的第一個階段,虛擬機要完成以下三個過程通過類的全限定名獲取定義此類的二進(jìn)制字節(jié)流。驗證目的是確保文件字節(jié)流信息符合虛擬機的要求。 引言 我們知道java代碼編譯后生成的是字節(jié)碼,那虛擬機是如何加載這些class字節(jié)碼文件的呢?加載之后又是如何進(jìn)行方法調(diào)用的呢? 一 類文件結(jié)構(gòu) 無關(guān)性基石 ja...

    RichardXG 評論0 收藏0
  • 深入理解虛擬機之虛擬機類加載機制

    摘要:最終形成可以被虛擬機最直接使用的類型的過程就是虛擬機的類加載機制。即重寫一個類加載器的方法驗證驗證是連接階段的第一步,這一階段的目的是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求,并且不會危害虛擬機自身的安全。 《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版》讀書筆記與常見相關(guān)面試題總結(jié) 本節(jié)常見面試題(推薦帶著問題閱讀,問題答案在文中都有提到): 簡單說說類加載過...

    MadPecker 評論0 收藏0
  • Java虛擬機類加載過程

    摘要:二驗證驗證主要是為了確保文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機的要求,并且不會危害虛擬機的自身安全。五初始化類的初始化階段是類加載過程的最后一步,該階段才真正開始執(zhí)行類中定義的程序代碼或者說是字節(jié)碼。 關(guān)注我,每天三分鐘,帶你輕松掌握一個Java相關(guān)知識點。 虛擬機(JVM)經(jīng)常出現(xiàn)在我們面試中,但是工作中卻很少遇到,導(dǎo)致很多同學(xué)沒有去了解過。其實除了應(yīng)付面試,作為java程序員,了解...

    lentoo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<