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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java中Mark接口_JVM源码分析之Java对象头实现

發(fā)布時(shí)間:2023/12/15 java 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中Mark接口_JVM源码分析之Java对象头实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原標(biāo)題:JVM源碼分析之Java對(duì)象頭實(shí)現(xiàn)

原創(chuàng)申明:本文由公眾號(hào)【猿燈塔】原創(chuàng),轉(zhuǎn)載請(qǐng)說明出處標(biāo)注

“365篇原創(chuàng)計(jì)劃”第十一篇。

今天呢!燈塔君跟大家講:

JVM源碼分析之Java對(duì)象頭實(shí)現(xiàn)

HotSpot虛擬機(jī)中,對(duì)象在內(nèi)存中的布局分為三塊區(qū)域:對(duì)象頭、實(shí)例數(shù)據(jù)和對(duì)齊填充。

對(duì)象頭

對(duì)象頭包括兩部分:Mark Word 和 類型指針。

Mark Word

Mark Word用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時(shí)間戳等等,占用內(nèi)存大小與虛擬機(jī)位長(zhǎng)一致。

類型指針

類型指針指向?qū)ο蟮念愒獢?shù)據(jù),虛擬機(jī)通過這個(gè)指針確定該對(duì)象是哪個(gè)類的實(shí)例。

markOop實(shí)現(xiàn)

HotSpot通過markOop類型實(shí)現(xiàn)Mark Word,具體實(shí)現(xiàn)位于markOop.hpp文件中。

由于對(duì)象需要存儲(chǔ)的運(yùn)行時(shí)數(shù)據(jù)很多,考慮到虛擬機(jī)的內(nèi)存使用,markOop被設(shè)計(jì)成一個(gè)非固定的數(shù)據(jù)結(jié)構(gòu),以便在極小的空間存儲(chǔ)盡量多的數(shù)據(jù),根據(jù)對(duì)象的狀態(tài)復(fù)用自己的存儲(chǔ)空間,32位虛擬機(jī)的markOop實(shí)現(xiàn)如下:

hash: 保存對(duì)象的哈希碼

age: 保存對(duì)象的分代年齡

biased_lock: 偏向鎖標(biāo)識(shí)位

lock: 鎖狀態(tài)標(biāo)識(shí)位

JavaThread:* 保存持有偏向鎖的線程ID

epoch: 保存偏向時(shí)間戳

markOop:中不同的鎖標(biāo)識(shí)位,代表著不同的鎖狀態(tài):

不同的鎖狀態(tài),存儲(chǔ)著不同的數(shù)據(jù):

markOop中提供了大量方法用于查看當(dāng)前對(duì)象頭的狀態(tài),以及更新對(duì)象頭的數(shù)據(jù),為synchronized鎖的實(shí)現(xiàn)提供了基礎(chǔ)。

下面來看看代碼吧:

首先定義兩個(gè)簡(jiǎn)單的類AAA和BBB

通過``javap -c AAA```查看編譯之后的字節(jié)碼,具體如下:

Java中的new關(guān)鍵字對(duì)應(yīng)jvm中的new指令,定義在InterpreterRuntime類中,實(shí)現(xiàn)如下:

new指令的實(shí)現(xiàn)過程:

1、其中pool是AAA的constant pool,此時(shí)AAA的class已經(jīng)加載到虛擬機(jī)中,new指令后面的#2表示BBB類全限定名的符號(hào)引用在constant pool的位置;

2、方法pool->klass_at負(fù)責(zé)返回BBB對(duì)應(yīng)的klassOop對(duì)象,實(shí)現(xiàn)如下:

如果常量池中指定位置(#2)的數(shù)據(jù)已經(jīng)是個(gè)oop類型,說明BBB的class已經(jīng)被加載并解析過,則直接通過(klassOop)entry.get_oop()返回klassOop;否則表示第一次使用BBB,需要解析BBB的符號(hào)引用,并加載BBB的class類,生成對(duì)應(yīng)的instanceKlass對(duì)象,并更新constant pool中對(duì)應(yīng)位置的符號(hào)引用;

3、klass->check_valid_for_instantiation可以防止抽象類被實(shí)例化;

4、klass->initialize實(shí)現(xiàn)如下:

如果BBB的instanceKlass對(duì)象已經(jīng)初始化完成,則直接返回;否則通過initialize_impl方法進(jìn)行初始化,整個(gè)初始化算法分成11步,具體實(shí)現(xiàn)如下:

step1

通過ObjectLocker在初始化之前進(jìn)行加鎖,防止多個(gè)線程并發(fā)初始化。

step2

step3

如果當(dāng)前instanceKlass處于being_initialized狀態(tài),且被當(dāng)前線程初始化,則直接返回。

其實(shí)對(duì)于這個(gè)step的處理我有疑問,什么情況會(huì)走到這一步?經(jīng)過RednaxelaFX大大提點(diǎn),如下情況會(huì)執(zhí)行step3:

例如A類有靜態(tài)變量指向一個(gè)new B類實(shí)例,B類里又有靜態(tài)變量指向new A類實(shí)例,這樣外部用A時(shí)要初始化A類,初始化過程中又要觸發(fā)B類初始化,B類初始化又再次觸發(fā)A類初始化。

如果當(dāng)前instanceKlass處于fully_initialized狀態(tài),說明已經(jīng)初始化完成,則直接返回;

step5

如果當(dāng)前instanceKlass處于initialization_error狀態(tài),說明初始化失敗了,拋出異常。

step6

設(shè)置當(dāng)前instanceKlass的狀態(tài)為 being_initialized;設(shè)置初始化線程為當(dāng)前線程。

如果當(dāng)前instanceKlass不是接口類型,并且父類不為空,且還未初始化,則執(zhí)行父類的初始化。

step8

通過thisoop->callclass_initializer方法執(zhí)行靜態(tài)塊代碼,實(shí)現(xiàn)如下:

this_oop->class_initializer()可以獲取靜態(tài)代碼塊入口,最終通過JavaCalls::call執(zhí)行代碼塊邏輯,再下一層就是具體操作系統(tǒng)的實(shí)現(xiàn)了。

step9

如果初始化過程沒有異常,說明instanceKlass對(duì)象已經(jīng)初始完成,則設(shè)置當(dāng)前instanceKlass的狀態(tài)為 fully_initialized,最后通知其它線程初始化已經(jīng)完成;否則執(zhí)行step10 and 11。

step10 and 11

如果初始化發(fā)生異常,則設(shè)置當(dāng)前instanceKlass的狀態(tài)為 initialization_error,并通知其它線程初始化發(fā)生異常。

5、如果instanceKlass初始化完成,klass->allocate_instance會(huì)在堆內(nèi)存創(chuàng)建instanceOopDesc對(duì)象,即類的實(shí)例化;.

instanceOopDesc

當(dāng)在Java中new一個(gè)對(duì)象時(shí),本質(zhì)是在堆內(nèi)存創(chuàng)建一個(gè)instanceOopDesc對(duì)象。

instanceOopDesc在實(shí)現(xiàn)上繼承自oopDesc,其中oopDesc定義如下:

當(dāng)然,這只是 oopDesc的部分實(shí)現(xiàn),oopDesc包含兩個(gè)數(shù)據(jù)成員:_mark 和 _metadata。

1、_mark是markOop類型對(duì)象,用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時(shí)間戳等等,占用內(nèi)存大小與虛擬機(jī)位長(zhǎng)一致,更具體的實(shí)現(xiàn)可以閱讀 《java對(duì)象頭的HotSpot實(shí)現(xiàn)分析》

2、_metadata是一個(gè)聯(lián)合體,其中wideKlassOop和narrowOop都是指向InstanceKlass對(duì)象的指針,wide版是普通指針,narrow版是壓縮類指針(compressed Class pointer)

instanceOopDesc對(duì)象的創(chuàng)建過程

instanceOopDesc對(duì)象通過instanceKlass::allocate_instance進(jìn)行創(chuàng)建,實(shí)現(xiàn)過程如下:

1、has_finalizer判斷當(dāng)前類是否包含不為空的finalize方法;

2、size_helper確定創(chuàng)建當(dāng)前對(duì)象需要分配多大內(nèi)存;

3、CollectedHeap::obj_allocate從堆中申請(qǐng)指定大小的內(nèi)存,并創(chuàng)建instanceOopDesc對(duì)象,實(shí)現(xiàn)如下:

4、如果當(dāng)前類重寫了finalize方法,且非空,需要把生成的對(duì)象封裝成Finalizer對(duì)象并添加到 Finalizer鏈表中,對(duì)象被GC時(shí),如果是Finalizer對(duì)象,會(huì)將對(duì)象賦值到pending對(duì)象。Reference Handler線程會(huì)將pending對(duì)象push到queue中,Finalizer線程poll到對(duì)象,先刪除掉Finalizer鏈表中對(duì)應(yīng)的對(duì)象,然后再執(zhí)行對(duì)象的finalize方法;

365天干貨不斷微信搜索「猿燈塔」第一時(shí)間閱讀,回復(fù)【資料】【面試】【簡(jiǎn)歷】有我準(zhǔn)備的一線大廠面試資料和簡(jiǎn)歷模板

責(zé)任編輯:

總結(jié)

以上是生活随笔為你收集整理的java中Mark接口_JVM源码分析之Java对象头实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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