Java 是門面向對象的開發語言,那麼咱們本身編寫的 Java 類生成的對象是什麼樣的?它確定保存在虛擬機的內存中,但它以怎樣的結構來保存的呢?帶着疑問往下看看。數組
Java 層的開發可能不太熟悉 Klass,但確定熟悉 class,咱們只要知道 Klass 是 class 在 JVM 中的表示便可,即 Java class 對應 JVM Klass。C++ 中的繼承關係以下:bash
class MetaspaceObj
class Metadata
class Klass
複製代碼
Klass 類用來描述 Java 類信息,包括描述類型自身佈局、類名、父類、子類、兄弟類等等。併發
按前面 class 對應的方式,那麼對象也應該有 JVM 內部與之相對應的表示吧?沒錯,就是 oop(ordinary object pointer),普通對象指針。它的定義以下:機器學習
typedef class oopDesc* oop;
複製代碼
其中 oopDesc 類是全部 oop 的基類。在 JVM 中,不一樣的 oop 用於描述特定類型的對象。好比類對象用 instanceOopDesc,數組用 arrayOopDesc。分佈式
Java 對象在 JVM 中的結構以下,包括 header 和對象內容。以下圖中,左邊的是 instanceOopDesc,即通常的類對象,header 包括了標識和元數據,標識用於存儲運行時記錄信息,包括哈希碼、GC鎖和線程鎖等等。而右邊的爲 arrayOopDesc,即數組對象,header 多了個 length,用於記錄數組長度。oop
public class Test {
private String[] flag = { "a", "b", "c" };
private String name = "test";
public static void main(String[] args) throws Exception {
Test test = new Test();
String _name = "test";
System.out.println(test.flag);
System.out.println(_name);
}
}
複製代碼
在上面程序中打個斷點,經過 jps 查出 pid,而後使用下面命令打開 hsdb,根據 pid 鏈接到 JVM。佈局
jhsdb hsdb
複製代碼
查看 main 線程的棧內存,咱們主要是要拿到 Test 對象的地址,即0x000000008a105dd0
。學習
接着用 inspector 來查看0x000000008a105dd0
地址對應的 oop,看到這個 oop 就是咱們的 Test 類生成的對象結構了,包含了 mark 和 metadata。這裏可能會有個疑問,就是前面不是說數組還有一個 length 來表示數組長度的嗎?但圖中的 flag 數組變量並無看到 length 啊。ui
其實數組 oop 並非沒有 length,而是 C++ 並無聲明這個變量,而是經過指針來直接將數組長度保存到對應的內存了,因此這裏是看不到的。經過下面具體的實現代碼就能清楚瞭解到緣由了。是否是咱們就沒辦法看到這個長度值呢?並非,下面繼續看如何來看這個值。this
int length() const {
return *(int*)(((intptr_t)this) + length_offset_in_bytes());
}
void set_length(int length) {
*(int*)(((intptr_t)this) + length_offset_in_bytes()) = length;
}
複製代碼
前面咱們能夠獲得 flag 數組 oop 的地址爲0x000000008a105de8
。64位機器上_mark
爲8字節,_metadata
爲4字節,那麼將地址加12,獲得0x000000008a105df4
。而後用 hsdb 命令行的 examine 獲得地址的值,獲得0x8a105e0800000003
,其中00000003
即是。
hsdb> examine 0x000000008a105df4
0x000000008a105df4: 0x8a105e0800000003
複製代碼
-------------推薦閱讀------------
跟我交流,向我提問:
公衆號的菜單已分爲「讀書總結」、「分佈式」、「機器學習」、「深度學習」、「NLP」、「Java深度」、「Java併發核心」、「JDK源碼」、「Tomcat內核」等,可能有一款適合你的胃口。
歡迎關注: