JVM重新認識(一)oop-klass模型--HSDB使用驗證


 

一:oop-kclass模型

思考:我們平時寫的java類編譯成.class文件,JVM加載.class文件,那么加載.class文件之后在JVM中就是oop-kclass(C++)模型形式存在的。

 JVM內部基於oop-klass模型描述一個java類以及其實例(對象),java類元信息用klass描述,對象用oop來描述。

oop: ordinary object pointer,也即普通對象指針.oop成員眾多

 

 

 

 這里有個問題,不是說xxxoop嗎?怎么類圖上怎么就是xxxppDesc了?
原因在於c++描述oop的層級關系時在 oopsHierarchy.hpp 中進行了如下定義:

typedef class  oopDesc*                            oop; 
typedef class   instanceOopDesc*            instanceOop; 
typedef class   methodOopDesc*                    methodOop; 
typedef class   constMethodOopDesc*            constMethodOop; 
typedef class   methodDataOopDesc*            methodDataOop; 
typedef class   arrayOopDesc*                    arrayOop; 
typedef class     objArrayOopDesc*            objArrayOop; 
typedef class     typeArrayOopDesc*            typeArrayOop; 
typedef class   constantPoolOopDesc*            constantPoolOop; 
typedef class   constantPoolCacheOopDesc*   constantPoolCacheOop; 
typedef class   symbolOopDesc*                    symbolOop;
typedef class   klassOopDesc*                    klassOop; 
typedef class   markOopDesc*                    markOop; 
typedef class   compiledICHolderOopDesc*    compiledICHolderOop;
View Code

其中各類的說明如下:

類名 說明
oop oop的頂級父類
instanceOop 表示java類實例
methodOop 表示java方法
constMethodOop 表示java方法中的只讀信息(其實就是字節碼指令)
methodDataOop 表示性能統計的相關數據
arrayOop 數組對象,定義了數組oops的抽象基類
objArrayOop 表示引用類型數組對象
typeArrayOop 表示基本類型數組對象
constantPoolOop 表示java字節碼文件中的常量池
constantPoolCacheOop 與constantPoolOop 相伴生,是后者的緩存對象,緩存了字段和方法的訪問信息,為允許時環境快速訪問字段和方法提供重要作用
symbolOop symbolOop是規范化字符串。所有symbolOop都位於全局符號表中。
klassOop 指向jvm內部的klass實例的對象
markOop oop 的標記對象,表示對象頭
compiledICHolderOop 內聯緩存實現的幫助器對象。它包含從編譯到解釋調用轉換時使用的中間值(method+klass對),總是分配在永久區(以避免在清除期間遍歷codecache)

上面的一個類就是描述我們平常創建的Java實例:instanceOopDesc,對象在內存中的布局就是通過它來表示的,關於這一點可以參考之前寫的關於

《關於Object=new Object();的美團六問》:https://blog.csdn.net/A7_A8_A9/article/details/105730007   的文章。

  里面有個關於對象的內存圖:

 

 總結起來就是:

instanceOopDesc包含如下信息:
1. 對象頭,也叫Mark Word,主要存儲對象運行時記錄信息,如hashcode, GC分代年齡,鎖狀態標志,線程ID,時間戳等;
2. 元數據指針class pointer,即指向方法區的instanceKlass實例 (虛擬機通過這個指針來群定這個對象是哪個類的實例。)
3. 實例數據 instance data;
4. 另外,如果是數組對象,還多了一個數組長度

5:對齊填充(有時候不需要)

klass

  1. klass 提供一個與java類對等的c++類型描述
  2. klass 提供虛擬機內部的函數分發機制
  3. jvm在加載class時,會創建instanceKlass,表示其元數據,包括常量池、字段、方法等,存放在方法區;instanceKlass是jvm中的數據結構;
    在new一個對象時,jvm創建instanceOopDesc,來表示這個對象,存放在堆區,其引用,存放在棧區;它用來表示對象的實例信息,看起來像個指針實際上是藏在指針里的對象;instanceOopDesc對應java中的對象實例;
  4. klass是在方法區的。
  5.  普通的Java類和數組用不同的kclass來表示,后面使用HSDB工具可以看到JVM運行時常量池中的Java實例存在的形式。

之間oop-klass之間的聯系:

handle

除了oop,kclass外在JVM中還有一個東西handle:

handle 是對oop的行為的封裝.這里需要注意的是:

  1. 大多數情況下,JVM在訪問java類時是一定通過handle的_handle 來得到oop,再通過oop獲得對應的klass,這樣,handle就能夠訪問oop的函數了.
  2. 如果是調用JVM內部的c++類所對應的oop函數,則不需要通過handle,直接通過oop拿到指定的klass即可.

三者的關系如下:

 

 

vtable: 該類所有的函數(除了static, final)和 父類的函數虛擬表。

Itable: 該類所有實現接口的函數列表.

 

二:使用HSDB查看JVM中運行時的內容

HSDB是JDK自帶的分析JVM的利器,運行方式在jdk安裝目錄/lib下有一個 sa-jdi.jar ,運行命令:java -cp  sa-jdi.jar sun.jvm.hotspot.HSDB

注意項目上用的jdk和環境配置的jdk要一致,不然就要指定上面那個java是哪個jdk版本的。

運行完會打開如下界面:

 

 用的測試例子如下:已經在運行

 

 

我們查看這個進程的id:

 

 得到id之后,操作如下

 

 

 

 把剛才的id  cp進去點擊ok

 

 等待一會出現當前進程的線程棧:

 

選中main線程,點擊Tool下的class browser

 

 

看到當前線程所涉及到的類,

 

 

 @后面是地址,我們cp下TestLog的地址:

 

 

 

填入下面的位置回車:我們就可以看到在JVM中我們定義的TestLog其實是用InstanceKlass來表示的。

我們看到TestLog的Class在JVM中也是用Oop表示的。

1:HotSpot並不把instanceKlass暴露給Java,而會另外創建對應的instanceOopDesc來表示java.lang.Class對象,並將后者稱為前者的“Java鏡像”就是圖中看到的'_java_mirror'屬性。

2:InstanceKlass持有指向oop引用(_java_mirror便是該instanceKlass對Class對象的引用)。

3:new操作返回的是對instanceOopDesc類型的引用(在棧中),而instanceOopDesc指針(堆中)指向instanceKlass(方法區),而instanceKlass指向了對應的類型的Class實例的instanceOopDesc(就是那個_java_mirror)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM