亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java類加載之Class對(duì)象到Klass模型詳解

 更新時(shí)間:2023年08月30日 10:07:34   作者:云下牧羊人  
這篇文章主要介紹了Java類加載之Class對(duì)象到Klass模型詳解,每一個(gè)Java類在JVM中都會(huì)對(duì)應(yīng)創(chuàng)建一個(gè)C++類實(shí)例,我們稱這個(gè)C++類為Klass實(shí)例,Klass實(shí)例里面存儲(chǔ)了java類中所描述的方法、字段、屬性等,需要的朋友可以參考下

前言

JVM只認(rèn)識(shí)Class文件,也就是說(shuō),任何一門計(jì)算機(jī)語(yǔ)言,只要它最后將代碼編譯成class文件,都能被JVM所執(zhí)行。

Kotlin、Groovy、JRuby、Jython、Scala等語(yǔ)言就是如此。

一、什么是Class文件

1. class文件是Java代碼經(jīng)過(guò)Javac編譯后生成的字節(jié)碼文件,如下圖所示。

圖1

2. class文件主要包含了魔數(shù)、JVM版本號(hào)、常量池、常量池計(jì)數(shù)器、訪問(wèn)標(biāo)識(shí)等信息,如下圖所示(截取自 Java虛擬機(jī)規(guī)范)

在這里插入圖片描述

  • magic:魔數(shù),占4字節(jié)。作用是判斷這個(gè)文件是否為一個(gè)虛擬機(jī)所能接受的class文件
  • minor_version::副版本號(hào),占2字節(jié),最小支持版本號(hào)。
  • major_version:主版本號(hào),占2字節(jié),最大支持版本號(hào)。
  • constant_pool_count:常量池計(jì)數(shù)器,記錄常量池表中的成員數(shù),它的值為常量池表中的成員數(shù)+1,常量池表的索引值只有在大于0并且小于constant_pool_count時(shí)才認(rèn)為是有效。
  • constant_pool:常量池,包含class文件結(jié)構(gòu)及其子結(jié)構(gòu)中所引用的所有字符串常量、類或接口、字段名和其他常量。
  • access_flag:訪問(wèn)標(biāo)志,用于表示類或接口的訪問(wèn)權(quán)限及屬性。
  • this_class:類索引。
  • super_class:父類索引。
  • interfaces_count:接口計(jì)數(shù)器。
  • interfaces_count[]:接口表。
  • fields_count:字段計(jì)數(shù)器。
  • fields:字段表。
  • methods_count:方法計(jì)數(shù)器。
  • methods[]:方法表。
  • attributes_count:屬性計(jì)數(shù)器。
  • attributes[]:屬性表。

3. 每一個(gè)Java類在JVM中都會(huì)對(duì)應(yīng)創(chuàng)建一個(gè)C++類實(shí)例,我們稱這個(gè)C++類為Klass實(shí)例(對(duì)應(yīng)hotspot源碼中的instanceKlass類)。

Klass實(shí)例里面存儲(chǔ)了java類中所描述的方法、字段、屬性等。

如下圖所示,instanceKlass的字段皆為存儲(chǔ)java類文件中的數(shù)據(jù)所設(shè)計(jì),詳見(jiàn)hotspot源碼中 instanceKlass.hpp文件。

在這里插入圖片描述

ps:JVM在創(chuàng)建InstanceKlass對(duì)象時(shí),為其申請(qǐng)的內(nèi)存空間,遠(yuǎn)超instanceKlass本身所需要得空間,這是因?yàn)镮nstanceKlass還要存虛表、接口表、以及Java類中的引用類型表。

二、class類加載的過(guò)程

你每寫(xiě)的一個(gè)Java類,在JVM中,都有一個(gè)對(duì)應(yīng)的C++類實(shí)例,這個(gè)C++類實(shí)例,我們管它叫Klass類,它存儲(chǔ)了類的元信息(常量池、屬性、方法等)。

1. 加載階段

  • 通過(guò)類的全限定名獲取java類編譯后生成的class文件,加載進(jìn)JVM,并解析class文件。
  • 解析完成后,JVM便會(huì)在內(nèi)部創(chuàng)建一個(gè)與Java類對(duì)等的類模板對(duì)象 instanceKlass實(shí)例(也是C++的一個(gè)類,里面保存了java類的常量池、方法、屬性等信息)。

下面奉上hotspot源碼解析常量池、字段、方法并創(chuàng)建對(duì)應(yīng)的Klass對(duì)象部分,代碼皆在ClassFileParser.cpp的 parseClassFile方法中,有興趣的同學(xué)可以自己看一看。

以下僅截取部分主要代碼

instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
                                                    ClassLoaderData* loader_data,
                                                    Handle protection_domain,
                                                    KlassHandle host_klass,
                                                    GrowableArray<Handle>* cp_patches,
                                                    TempNewSymbol& parsed_name,
                                                    bool verify,
                                                    TRAPS) {
  // Constant pool   解析常量池
  constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
 //......
    //解析Java類字段
    Array<u2>* fields = parse_fields(class_name,
                                     access_flags.is_interface(),
                                     &fac, &java_fields_count,
                                     CHECK_(nullHandle));
    //......
    //解析Java類方法
    Array<Method*>* methods = parse_methods(access_flags.is_interface(),
                                            &promoted_flags,
                                            &has_final_method,
                                            &declares_default_methods,
                                            CHECK_(nullHandle));
    //....
    // 開(kāi)始創(chuàng)建與Java對(duì)等的Klass對(duì)象
    _klass = InstanceKlass::allocate_instance_klass(loader_data,
                                                    vtable_size,
                                                    itable_size,
                                                    info.static_field_size,
                                                    total_oop_map_size2,
                                                    rt,
                                                    access_flags,
                                                    name,
                                                    super_klass(),
                                                    !host_klass.is_null(),
                                                    CHECK_(nullHandle));
}

4.通過(guò)instanceKlass生成一個(gè)鏡像類,放在堆區(qū),即instanceMirrorKlass實(shí)例(對(duì)應(yīng)hotspot源碼中的 instanceMirrorKlass類)。

instanceKlass供jvm內(nèi)部使用,小編認(rèn)為多生成一個(gè)instanceMirrorKlass是因?yàn)榭紤]到運(yùn)行安全因素,不能直接把類暴露給外部使用,所以弄出了個(gè)鏡像類實(shí)例提供給外部程序調(diào)用。

小貼紙:

1.java類中的靜態(tài)變量會(huì)存儲(chǔ)在instanceMirrorKlass類中,instanceMirrorKlass類里面比instanceKlass類多定義了一個(gè)靜態(tài)字段偏移量的屬性,可以通過(guò)該屬性獲取靜態(tài)變量。

在這里插入圖片描述

2.Java中的數(shù)組類在運(yùn)行時(shí)數(shù)據(jù)區(qū)的生成的實(shí)例為

方法區(qū):ArrayKlass。堆區(qū):基本類型數(shù)組 TypeArrayKlass,引用類型數(shù)組ObjArrayKlass 分別對(duì)應(yīng)hotspot源碼里的TypeArrayKlass.cpp 與 ObjArrayKlass.cpp類

3.類加載器是什么時(shí)候加載的,如下圖,hotspot源碼java.c中有一個(gè)javaMain方法,javaMain 里面調(diào)用了LoadMainClass 方法,你的一切疑惑都在LoadMainClass里面,它的執(zhí)行邏輯是通過(guò)啟動(dòng)類加載器加載類sun.launcher.LauncherHelper,執(zhí)行該類的方法checkAndLoadMain,加載main函數(shù)所在的類,啟動(dòng)擴(kuò)展類加載器、應(yīng)用類加載器也是在這個(gè)時(shí)候完成的。

在這里插入圖片描述

2. 驗(yàn)證

驗(yàn)證主要就是對(duì)Java虛擬機(jī)定義的一些約束進(jìn)行校驗(yàn),如果校驗(yàn)不通過(guò)就拋出異常。

  • 靜態(tài)約束:
  • 結(jié)構(gòu)化約束

3. 準(zhǔn)備

創(chuàng)建類或接口的靜態(tài)字段,并用默認(rèn)值初始化這些字段。這個(gè)階段不會(huì)執(zhí)行任何的虛擬機(jī)字節(jié)碼指令。

數(shù)據(jù)類型默認(rèn)值
byte(byte)0
shot(shot)0
long0L
char‘\u0000’
int0
float0.0f
double0.0d
boolean0(false)

final修飾類的變量,已經(jīng)不會(huì)再 發(fā)生變化,所以在準(zhǔn)備階段就進(jìn)行賦值了,就沒(méi)有賦初值這個(gè)操作了。

4. 解析

我們從各種某度的文章里總會(huì)看到,解析的主要過(guò)程就是將符號(hào)引用替換為直接引用。

那么什么是符號(hào)引用呢? 如下圖,下圖采用了jclasslib插件展示一個(gè)Java類文件編譯后產(chǎn)生的class文件信息。

我們可以看到方法里面字節(jié)碼指令后面的 #1等符號(hào)就是我們常說(shuō)的符號(hào)引用。

在這里插入圖片描述

這個(gè)符號(hào)引用其實(shí)就是常量池中的索引(例如#1指向的就是常量池中的第一個(gè)類或方法) 如下圖所示

在這里插入圖片描述

JVM會(huì)在準(zhǔn)備階段將這些索引符號(hào)替換為直接內(nèi)存地址。以供后續(xù)JVM指令進(jìn)行調(diào)用。

都有那些虛擬機(jī)指令需要進(jìn)行符號(hào)引用的解析呢?

anewarray、checkcast、getfield、getstatic、instanceof、nvokedynamic、invokeinterface、invokespecial、invokestatic、invokevirtual、ldc、ldc_w、multianewarray、new、putfield、putstatic

執(zhí)行上述任何一條指令都需要對(duì)它的符號(hào)引用進(jìn)行解析。

如果在某個(gè)符號(hào)引用解析過(guò)程中發(fā)生錯(cuò)誤,那么應(yīng)該在使用該符號(hào)引用的程序處拋出IncompatibleClassChangeError或者其子類的異常

5. 初始化

初始化就是 執(zhí)行類的靜態(tài)代碼塊,并且完成靜態(tài)變量的賦值,我們可以看到

如下圖,如果我們的代碼里要是有靜態(tài)變量,并且對(duì)靜態(tài)變量進(jìn)行賦值了,那么生成的字節(jié)碼文件中就會(huì)有clinit方法。

這個(gè)clinit就是執(zhí)行靜態(tài)變量賦值的指令,而且方法中語(yǔ)句的先后順序與代碼的編寫(xiě)順序相關(guān)

在這里插入圖片描述

既然初始化的時(shí)候可以直接對(duì)變量進(jìn)行賦值,那我們是否可以跳過(guò)準(zhǔn)備階段,直接在初始化階段進(jìn)行賦值

。因?yàn)闇?zhǔn)備階段主要是賦初值,那我們可以直接要我們寫(xiě)的值,不要初始值。 答案當(dāng)然是不行,原因如下

初始化階段主要是依靠clinit方法生成的指令進(jìn)行賦值,但是如果我們定義一個(gè)空的靜態(tài)變量,那clinit方法中就不會(huì)生成這個(gè)靜態(tài)變量相關(guān)的賦值代碼。

如下圖,所以這時(shí)就需要準(zhǔn)備階段給這個(gè)靜態(tài)變量初始化、賦初值,否則這個(gè)變量就丟掉了。

在這里插入圖片描述

初始化之后就由JVM的執(zhí)行引擎進(jìn)行取指執(zhí)行了,執(zhí)行引擎有些過(guò)于復(fù)雜,以后有機(jī)會(huì)再分析吧。

總結(jié)

  1. JVM能執(zhí)行的就是Class文件,所有計(jì)算機(jī)語(yǔ)言只要最后生成了Class文件,都可以交給JVM執(zhí)行。Kotlin、Groovy、JRuby、Jython、Scala等語(yǔ)言就是如此。
  2. 由于JVM是由C/C++編寫(xiě)的,所以每一個(gè)Java類加載到JVM時(shí)都會(huì)生成一個(gè)對(duì)應(yīng)的C++類,即instanceKlass,存放在方法區(qū)(元空間)。同時(shí)生成一個(gè)instanceKlass的實(shí)例對(duì)象,即instanceMirrorKlass,放在堆區(qū)。
  3. JVM類加載機(jī)制分為,加載、驗(yàn)證、準(zhǔn)備、解析、初始化五個(gè)階段。
  4. 加載階段:
    通過(guò)類的全限定名獲取存儲(chǔ)該類的class文件,并對(duì)其進(jìn)行解析
    解析后生成對(duì)應(yīng)的C++模板類,即instanceKlass實(shí)例,存放在元空間,用于JVM內(nèi)部使用
    在堆區(qū)生成該類的Class對(duì)象實(shí)例,即instanceMirrorKlass,用于其他系統(tǒng)或程序進(jìn)行調(diào)用。
  5. 驗(yàn)證階段主要有靜態(tài)約束校驗(yàn),結(jié)構(gòu)化約束校驗(yàn)兩種。
  6. 準(zhǔn)備階段主要是對(duì)靜態(tài)變量賦初值的操作
  7. 解析階段就是將符號(hào)引用(常量池索引)替換為直接引用(方法內(nèi)存地址)
  8. 初始化就是 執(zhí)行類的靜態(tài)代碼塊,并且完成靜態(tài)變量的賦值。賦值的指令會(huì)生成在clinit方法中,當(dāng)在Java代碼中對(duì)靜態(tài)變量賦值了,clinit中才會(huì)生成對(duì)應(yīng)的指令。

擴(kuò)展問(wèn)題

  • 類的初始化階段會(huì)不會(huì)有線程安全問(wèn)題?
  • 類加載階段會(huì)使用synchronized鎖機(jī)制嗎?
  • 類加載時(shí)延遲偏向鎖的原因?
  • 如果實(shí)現(xiàn)一個(gè)類加載器,不按照類加載器機(jī)制實(shí)現(xiàn)可不可以?

到此這篇關(guān)于Java類加載之Class對(duì)象到Klass模型詳解的文章就介紹到這了,更多相關(guān)Java的Class對(duì)象到Klass模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談Java finally語(yǔ)句到底是在return之前還是之后執(zhí)行(必看篇)

    淺談Java finally語(yǔ)句到底是在return之前還是之后執(zhí)行(必看篇)

    下面小編就為大家?guī)?lái)一篇淺談Java finally語(yǔ)句到底是在return之前還是之后執(zhí)行(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Java異常堆棧打印次數(shù)限制機(jī)制用法詳解

    Java異常堆棧打印次數(shù)限制機(jī)制用法詳解

    在Java開(kāi)發(fā)中,異常處理是保證程序健壯性的重要手段,但當(dāng)同一個(gè)異常被頻繁拋出時(shí),日志可能會(huì)被大量重復(fù)的堆棧信息淹沒(méi),影響問(wèn)題排查效率,所以本文給大家介紹了Java異常堆棧打印次數(shù)限制機(jī)制的用法,需要的朋友可以參考下
    2025-04-04
  • Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解

    Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解

    這篇文章主要介紹了Thymeleaf 3.0 自定義標(biāo)簽方言屬性的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • 詳解SpringMVC常用注解功能及屬性

    詳解SpringMVC常用注解功能及屬性

    這篇文章主要介紹了詳解SpringMVC注解功能及屬性,文中通過(guò)詳細(xì)的示例代碼作了簡(jiǎn)要的分析,有需要的朋友可以借鑒參考下,希望可以有所幫助
    2021-09-09
  • Java實(shí)現(xiàn)貪吃蛇游戲源碼

    Java實(shí)現(xiàn)貪吃蛇游戲源碼

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)貪吃蛇游戲源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • SpringBoot復(fù)雜參數(shù)應(yīng)用詳細(xì)講解

    SpringBoot復(fù)雜參數(shù)應(yīng)用詳細(xì)講解

    我們?cè)诰帉?xiě)接口時(shí)會(huì)傳入復(fù)雜參數(shù),如Map、Model等,這種類似的參數(shù)會(huì)有相應(yīng)的參數(shù)解析器進(jìn)行解析,并且最后會(huì)將解析出的值放到request域中,下面我們一起來(lái)探析一下其中的原理
    2022-09-09
  • 使用Spring事物時(shí)不生效的場(chǎng)景及解決方法

    使用Spring事物時(shí)不生效的場(chǎng)景及解決方法

    今天介紹一下Spring事物不生效的場(chǎng)景,事物是我們?cè)陧?xiàng)目中經(jīng)常使用的,如果是Java的話,基本上都使用Spring的事物,不過(guò)Spring的事物如果使用不當(dāng),那么就會(huì)導(dǎo)致事物失效或者不回滾,最終導(dǎo)致數(shù)據(jù)不一致,下面我們意義列舉不生效的場(chǎng)景,并給出解決方法
    2023-09-09
  • ConcurrentHashMap是如何保證線程安全

    ConcurrentHashMap是如何保證線程安全

    大家好,本篇文章主要講的是ConcurrentHashMap是如何保證線程安全,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-01-01
  • java實(shí)現(xiàn)哈夫曼文件解壓縮

    java實(shí)現(xiàn)哈夫曼文件解壓縮

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)哈夫曼文件解壓縮,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Java Lock接口實(shí)現(xiàn)原理及實(shí)例解析

    Java Lock接口實(shí)現(xiàn)原理及實(shí)例解析

    這篇文章主要介紹了Java Lock接口實(shí)現(xiàn)原理及實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04

最新評(píng)論