您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)如何用JVM源碼分析Java對(duì)象的創(chuàng)建過(guò)程,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
基于HotSpot實(shí)現(xiàn)對(duì)Java對(duì)象的創(chuàng)建過(guò)程進(jìn)行深入分析。
定義兩個(gè)簡(jiǎn)單的類AAA和BBB
通過(guò)“javap -c AAA“`查看編譯之后的字節(jié)碼,具體如下:
Java中的new關(guān)鍵字對(duì)應(yīng)jvm中的new指令,定義在InterpreterRuntime類中,實(shí)現(xiàn)如下:
new指令的實(shí)現(xiàn)過(guò)程:
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類型,說(shuō)明BBB的class已經(jīng)被加載并解析過(guò),則直接通過(guò)(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)初始化完成,則直接返回;否則通過(guò)initialize_impl
方法進(jìn)行初始化,整個(gè)初始化算法分成11步,具體實(shí)現(xiàn)如下:
通過(guò)ObjectLocker在初始化之前進(jìn)行加鎖,防止多個(gè)線程并發(fā)初始化。
如果當(dāng)前instanceKlass處于being_initialized狀態(tài),且正在被其它線程初始化,則執(zhí)行ol.waitUninterruptibly
等待其他線程完成后通知。
如果當(dāng)前instanceKlass處于being_initialized狀態(tài),且被當(dāng)前線程初始化,則直接返回。
其實(shí)對(duì)于這個(gè)step的處理我有疑問(wèn),什么情況會(huì)走到這一步?經(jīng)過(guò)RednaxelaFX大大提點(diǎn),如下情況會(huì)執(zhí)行step3:
例如A類有靜態(tài)變量指向一個(gè)new B類實(shí)例,B類里又有靜態(tài)變量指向new A類實(shí)例,這樣外部用A時(shí)要初始化A類,初始化過(guò)程中又要觸發(fā)B類初始化,B類初始化又再次觸發(fā)A類初始化。
如果當(dāng)前instanceKlass處于fully_initialized狀態(tài),說(shuō)明已經(jīng)初始化完成,則直接返回;
如果當(dāng)前instanceKlass處于initialization_error狀態(tài),說(shuō)明初始化失敗了,拋出異常。
設(shè)置當(dāng)前instanceKlass的狀態(tài)為 being_initialized;設(shè)置初始化線程為當(dāng)前線程。
如果當(dāng)前instanceKlass不是接口類型,并且父類不為空,且還未初始化,則執(zhí)行父類的初始化。
通過(guò)this_oop->call_class_initializer
方法執(zhí)行靜態(tài)塊代碼,實(shí)現(xiàn)如下:
this_oop->class_initializer()
可以獲取靜態(tài)代碼塊入口,最終通過(guò)JavaCalls::call
執(zhí)行代碼塊邏輯,再下一層就是具體操作系統(tǒng)的實(shí)現(xiàn)了。
如果初始化過(guò)程沒(méi)有異常,說(shuō)明instanceKlass對(duì)象已經(jīng)初始完成,則設(shè)置當(dāng)前instanceKlass的狀態(tài)為 fully_initialized,***通知其它線程初始化已經(jīng)完成;否則執(zhí)行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í)例化;
當(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ì)象通過(guò)instanceKlass::allocate_instance
進(jìn)行創(chuàng)建,實(shí)現(xiàn)過(guò)程如下:
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中,F(xiàn)inalizer線程poll到對(duì)象,先刪除掉Finalizer鏈表中對(duì)應(yīng)的對(duì)象,然后再執(zhí)行對(duì)象的finalize方法;
關(guān)于如何用JVM源碼分析Java對(duì)象的創(chuàng)建過(guò)程就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。