search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

JVM源碼分析之Java類的載入過程

最近對Java細節的底層實現比較感興趣,如Java類文件是如何載入到虛擬機的,類對象和方法是以什麼數據結構存在於虛擬機中?虛方法、實例方法和靜態方法是如何調用的?本文基於openjdk-7的OpenJDK實現Java類在HotSpot的內部實現進行分析。

HotSpot內存劃分

在HotSpot實現中,內存被劃分成Java堆、方法區、Java棧、本地方法棧和PC寄存器幾個部分:1、Java棧和本地方法棧用於方法之間的調用,進棧出棧的過程;2、Java堆用於存放對象,在Java中,所有對象的創建都在堆上申請內存,並被GC管理;3、方法區分成PermGen和CodeCache:PermGen存放Java類的相關信息,如靜態變數、成員方法和抽象方法等;CodeCache存放JIT編譯之後的本地代碼;

更詳細的相關內容可以閱讀《JVM內存的那些事》

HotSpot對象模型

HotSpot JVM並沒有根據Java對象直接通過虛擬機映射到新建的C++對象,而是設計了一個oop/klass model,其中oop為Ordinary Object Pointer,用來表示對象的實例信息;klass用來保存描述元數據。

Klass

關於為何要設計oop/klass這種二分模型的實現,一個原因是不想讓每個對象都包含vtbl(虛方法表),其中oop中不含有任何虛函數,虛函數表保存於klass中,可以進行method dispatch。

oop

oopDesc對象包含兩部分數據:_mark 和 _metadata;1、_mark是markOop類型對象,用於存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳等等,佔用內存大小與虛擬機位長一致,更具體的實現可以閱讀 java對象頭的HotSpot實現分析。2、_metadata是一個結構體,wideKlassOop和narrowOop都指向InstanceKlass對象,其中narrowOop指向的是經過壓縮的對象;3、_klass欄位建立了oop對象與klass對象之間的聯繫;

HotSpot如何載入並解析class文件

class文件在虛擬機的整個生命周期包括載入、驗證、準備、解析、初始化、使用和卸載7個階段,通過ClassLoader.loadClass方法可以手動載入一個Java類到虛擬機中,並返回Class類型的引用。

這裡並沒有自定義類載入器,而是利用ClassLoaderCase的類載入器進行載入類AAA。

loadClass方法實現

1、loadClass方法實現了雙親委派的類載入機制,如果需要自定義類載入器,建議重寫內部的findClass方法,而非loadClass方法;2、通過debug,可以發現loadClass方法最終會執行native方法defineClass1進行類的載入,即讀取對應class文件的二進位數據到虛擬機中進行解析;

class文件的解析

Java中的defineClass1方法是個native方法,說明依賴於底層的實現,在HotSpot中,其實現位於ClassLoader.c文件中,最終調用jvm.cpp中的jvm_define_class_common方法實現,核心的實現邏輯如下:

1、驗證全限定類名的長度,最大為(1 << 16) -1,如果長度超過 65535,就會拋出java/lang/NoClassDefFoundError異常,主要原因是constant pool不支持這麼長的字元串;2、SystemDictionary::resolve_from_stream處理stream數據流,並生成Klass對象。內部通過ClassFileParser.cpp的parseClassFile方法對class文件的數據流進行解析,代碼實在實在實在實在太長,有興趣的同學可以閱讀完整的實現,大概的過程如下:1、驗證當前magic為0xCAFEBABE;2、獲取class文件的minor_version、major_version,並判斷當前虛擬機是否支持該版本;3、通過parse_constant_pool方法解析當前class的常量池;4、解析當前class的access_flags;5、解析當前class的父類;6、解析當前class的介面;7、….

好吧,我得承認這塊邏輯很複雜…class數據流解析完成後,通過oopFactory::new_instanceKlass創建一個與之對應的instanceKlass對象,new_instanceKlass實現如下:

1、其中instanceKlassKlass::allocate_instance_klass方法會初始化一個空instanceKlass對象,並由後續邏輯進行數據的填充;2、但是發現該方法的返回類型並非是instanceKlass,而是klassOop類型;3、allocate_instance_klass方法的實現如下:

1、base_create_klass方法最終通過Klass::base_create_klass_oop方法創建Klass對象,這裡是instanceKlass對象,並返回對應的klassOop;2、k->klass_part獲取對應的Klass對象,並強制轉換成instanceKlass類型的對象;3、設置instanceKlass對象的默認值;

Klass對象如何創建?

上述的instanceKlass對象由Klass::base_create_klass_oop方法進行創建,實現如下:

1、allocate_permanent方法默認在PermGen分配內存,instanceKlass對象保存在永久代區域;2、Klass的as_klassOop方法可以獲取對應的klassOop,那klassOop到底是什麼?

klassOop相當於Java中的class,一個klassOop對象包含header、klass_field和Klass。

instanceKlass

可以發現,每個instanceKlass對象都有一個ClassState狀態,用來標識當前class的載入進度,另外instanceKlass對象中包含了如下欄位,描述class文件的信息。

instanceKlassKlass

instanceKlassKlass在實現上繼承了klassKlass類

全局只存在一個instanceKlassKlass對象,虛擬機啟動時,會在Universe::genesis方法中初始化。

虛擬機中所有instanceKlass對象的_klass欄位都指向該instanceKlassKlass對象,其初始化過程如下:

1、方法Universe::klassKlassObj獲取klassKlass對象;2、方法base_create_klass負責創建instanceKlassKlass對象,並返回對應的klassOop;3、方法java_lang_Class::create_mirror分配mirror,類似於一個鏡像,在java層面可以訪問到;

klassKlass

klassKlass在實現上繼承了Klass類

和instanceKlassKlass一樣,klassKlass對象也是全局唯一的,虛擬機啟動時,會在Universe::genesis方法中初始化,其初始化過程如下:

1、通過base_create_klass創建klassKlass對象,並返回對應的klassOop;

2、set_klass方法把自身設置成_klass;



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦