資源描述:
《在運(yùn)行期通過(guò)反射了解jvm內(nèi)部機(jī)制-java開(kāi)發(fā)java經(jīng)驗(yàn)技巧》由會(huì)員上傳分享,免費(fèi)在線閱讀,更多相關(guān)內(nèi)容在工程資料-天天文庫(kù)。
1、在運(yùn)行期通過(guò)反射了解JVM內(nèi)部機(jī)制-Java開(kāi)發(fā)Java經(jīng)驗(yàn)技巧在運(yùn)行期通過(guò)反射了解JVM內(nèi)部機(jī)制木文由ImportNew?黃飛飛翻譯自takipioncodeo歡迎加入翻譯小組。轉(zhuǎn)載請(qǐng)見(jiàn)文末要求。在F1常工作中,我們都習(xí)慣直接使用或者通過(guò)框架使用反射。在沒(méi)冇反射相關(guān)硬編碼知識(shí)的情況卜,這是Java和Scala編程中使用的類(lèi)庫(kù)與我們的代碼Z間進(jìn)行交互的一種主要手段。但是,使用反射僅限于JVM內(nèi)部運(yùn)行的Java和Scala代碼。假使在運(yùn)行期通過(guò)反射既能查看自己的代碼乂能看到JVM的代碼,會(huì)有怎樣的效果呢?當(dāng)我們開(kāi)始創(chuàng)建Takipi的時(shí)候,試圖尋找一種通過(guò)分析JVM堆內(nèi)存來(lái)進(jìn)
2、行一些底層優(yōu)化的有效方法,比如掃描一個(gè)托管堆塊(managedheapblock)的地址空間。我們找到了許多有趣的工具和組件用來(lái)檢測(cè)JVM狀態(tài)的各個(gè)方面,具屮一個(gè)就是在運(yùn)行期通過(guò)反射了解JVM內(nèi)部機(jī)制。譯注:Takipi是一家以色列創(chuàng)業(yè)公司,發(fā)現(xiàn)了一種構(gòu)建后端服務(wù)器網(wǎng)絡(luò)的新方式,可以使用非常簡(jiǎn)化的除錯(cuò)流程幫助企業(yè)定位錯(cuò)誤。Java可服務(wù)性代理(Scrviccablity?Agcnt,簡(jiǎn)寫(xiě)SA)是最強(qiáng)大和最底層的Java調(diào)試工具Z-o這個(gè)強(qiáng)大的工具是HotSpot?JDK自帶的。使用它不僅可以看到堆中的Java對(duì)象,還可以看到內(nèi)部C++?對(duì)彖,包押iJVM本身。那才是真正魔
3、法開(kāi)始的地方。反射的構(gòu)成:在運(yùn)行時(shí)動(dòng)態(tài)檢測(cè)和修改對(duì)象時(shí),無(wú)論使用何種形式的反射都不能缺少兩個(gè)必要信息。第一個(gè)是想耍檢測(cè)的對(duì)彖引用(或者地址);第二個(gè)是對(duì)象結(jié)構(gòu)描述,包括所有字段的偏移量以及它們的類(lèi)型信息。如果支持動(dòng)態(tài)方法調(diào)用,這個(gè)結(jié)構(gòu)還需要包括類(lèi)方法表(比如?vtable)的引用,以及每個(gè)方法需要的參數(shù)。Java反射本身是非常簡(jiǎn)單的,通過(guò)反射獲取目標(biāo)對(duì)象的引用與獲取其它方式一樣。使用Object.getClass?通用方法(最開(kāi)始從類(lèi)的字節(jié)碼中加載)獲取字段和方法結(jié)構(gòu)。真正的問(wèn)題是:如何反射JVM本身?反射的關(guān)鍵:令人驚奇的是,JVM通過(guò)一套公開(kāi)的輸出符號(hào)暴露了其內(nèi)部的類(lèi)
4、型系統(tǒng)。?這些符號(hào)給可服務(wù)性代理(或其他工具)提供了訪問(wèn)JVM內(nèi)部類(lèi)系統(tǒng)結(jié)構(gòu)和地址的方法。通過(guò)這些符號(hào),幾乎可以檢測(cè)到JVM內(nèi)部在最底層運(yùn)行機(jī)制的所有方面,包括諸如原始堆地址、線程/棧地址以及編譯器內(nèi)部狀態(tài)等。反射實(shí)戰(zhàn):為了增加對(duì)這種方式的了解,啟動(dòng)可服務(wù)性代理的HotSpot調(diào)試程序界面,可以看到止在運(yùn)行的一些功能。將sun.jvm.hotspot.HSDB作為主類(lèi)參數(shù)啟動(dòng)sa-jdi.jar,可以看到與其它JVM功能強(qiáng)大調(diào)試工具,例如?jmap、jinfo?和?jstack等,一樣的底層信息。HSDB及其為目標(biāo)JVM提供的一些非常底層的檢測(cè)功能具體實(shí)現(xiàn):讓我們仔細(xì)了解
5、這些出JV"提供的功能。這種方法的基礎(chǔ)是由?jvm函數(shù)庫(kù)公開(kāi)導(dǎo)出的gllotSpotVMStructs?結(jié)構(gòu)。這個(gè)結(jié)構(gòu)暴露了JVM內(nèi)部的類(lèi)型系統(tǒng),也為我們捉供了可以開(kāi)始反射的根對(duì)彖地址??梢酝ㄟ^(guò)?JN1?或者?JNA訪問(wèn)這個(gè)符號(hào),調(diào)用方式與訪問(wèn)動(dòng)態(tài)鏈接的操作系統(tǒng)公開(kāi)系統(tǒng)庫(kù)符號(hào)一樣。接下來(lái)問(wèn)題就變成:怎樣解析由?gHotSpotVMStructs符號(hào)小地址的數(shù)據(jù)?從下表中可以看到,JVM不僅暴露了類(lèi)型系統(tǒng)的地址以及根對(duì)象地址,還提供一些額外的符號(hào)用來(lái)解析需要的數(shù)據(jù)值。這些數(shù)據(jù)包括已定位的類(lèi)描述符及其二進(jìn)制偏移量。jvm.dl1暴露符號(hào)的一個(gè)dependencywalker截
6、圖清單(manifest):gHotSpotVMStructs結(jié)構(gòu)指向了類(lèi)及其字段的一個(gè)列表,每個(gè)類(lèi)提供了一個(gè)字段列表。對(duì)于每個(gè)字段,該結(jié)構(gòu)提供了它的名稱(chēng)、類(lèi)型以及是否靜態(tài)字段。如果是一個(gè)靜態(tài)字段,這個(gè)結(jié)構(gòu)述會(huì)捉供目標(biāo)對(duì)象的訪問(wèn)地址。該地址可用作反射JVM內(nèi)部特定組件的根,包括諸如編譯器、線程處理或者收集堆系統(tǒng)等。可以從這里檢出Hotspot?JDK中可服務(wù)性代理用來(lái)解析?gHotSpotVMStructs的實(shí)際算法。實(shí)例:既然已經(jīng)大概了解了這些功能,現(xiàn)在看一些由該接口訪問(wèn)數(shù)據(jù)類(lèi)型的示例。那些編寫(xiě)SA代理的人,在為gHotSpotVMStructs表中的類(lèi)創(chuàng)建Java封裝
7、時(shí)克服了很多麻煩。在訪問(wèn)大多數(shù)內(nèi)部系統(tǒng)時(shí),這些封裝提供一套簡(jiǎn)潔的API,不僅類(lèi)型安全而且還隱藏了一些解析數(shù)據(jù)所必須的二進(jìn)制工作。為了更好地了解這些API提供的強(qiáng)大功能,卜?面是其中的一些底層類(lèi)介紹:?VM?是一個(gè)單例類(lèi),它暴露了JVM的許多內(nèi)部系統(tǒng),比如線程系統(tǒng)、內(nèi)存管理以及集合功能。可以把它當(dāng)作JVM許多了系統(tǒng)的一個(gè)入口。當(dāng)你研究API時(shí),町以從這里入手。?JavaThread?可以讓你從JVM角度理解一個(gè)Java線程,?同時(shí)還有(編譯后的、經(jīng)過(guò)解釋的和本地)幀位直和類(lèi)型的深入信息以及實(shí)際的本地堆棧和CPU寄存器信息。?Co