Java物件在JVM中長啥樣

超人汪小建發表於2018-05-12

前言

Java 是門物件導向的開發語言,那麼我們自己編寫的 Java 類生成的物件是什麼樣的?它肯定儲存在虛擬機器的記憶體中,但它以怎樣的結構來儲存的呢?帶著疑問往下看看。

關於Klass

Java 層的開發可能不太熟悉 Klass,但肯定熟悉 class,我們只要知道 Klass 是 class 在 JVM 中的表示即可,即 Java class 對應 JVM Klass。C++ 中的繼承關係如下:

class MetaspaceObj
    class Metadata
        class Klass
複製程式碼

Klass 類用來描述 Java 類資訊,包括描述型別自身佈局、類名、父類、子類、兄弟類等等。

關於oop

按前面 class 對應的方式,那麼物件也應該有 JVM 內部與之相對應的表示吧?沒錯,就是 oop(ordinary object pointer),普通物件指標。它的定義如下:

typedef class oopDesc*                            oop;
複製程式碼

其中 oopDesc 類是所有 oop 的基類。在 JVM 中,不同的 oop 用於描述特定型別的物件。比如類物件用 instanceOopDesc,陣列用 arrayOopDesc。

Klass+oop模型

Java 物件在 JVM 中的結構如下,包括 header 和物件內容。如下圖中,左邊的是 instanceOopDesc,即一般的類物件,header 包括了標識和後設資料,標識用於儲存執行時記錄資訊,包括雜湊碼、GC鎖和執行緒鎖等等。而右邊的為 arrayOopDesc,即陣列物件,header 多了個 length,用於記錄陣列長度。

這裡寫圖片描述

來個demo

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 啊。

這裡寫圖片描述

其實陣列 oop 並不是沒有 length,而是 C++ 並沒有宣告這個變數,而是通過指標來直接將陣列長度儲存到對應的記憶體了,所以這裡是看不到的。通過下面具體的實現程式碼就能清楚瞭解到原因了。是不是我們就沒辦法看到這個長度值呢?並不是,下面繼續看如何來看這個值。

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
複製程式碼

-------------推薦閱讀------------

我的2017文章彙總——機器學習篇

我的2017文章彙總——Java及中介軟體

我的2017文章彙總——深度學習篇

我的2017文章彙總——JDK原始碼篇

我的2017文章彙總——自然語言處理篇

我的2017文章彙總——Java併發篇


跟我交流,向我提問:

這裡寫圖片描述

公眾號的選單已分為“讀書總結”、“分散式”、“機器學習”、“深度學習”、“NLP”、“Java深度”、“Java併發核心”、“JDK原始碼”、“Tomcat核心”等,可能有一款適合你的胃口。

為什麼寫《Tomcat核心設計剖析》

歡迎關注:

這裡寫圖片描述

相關文章