JVM(八):Java 對象模型

JVM(八):Java 對象模型

本文將學習對象是如何建立的,對象的內存佈局,以及如何定位訪問一個對象。java

對象建立

當虛擬機碰到一個new指令時,首先檢查指令參數可否在常量池中定位一個類的符號引用,而且檢查該符號引用對應的類是否已經被加載,解析和初始化。當一切都肯定完成後,JVM就會爲其分配內存(須要分配的內存大小在如今就已經肯定,在 下面 中詳細講述)。算法

對象的內存分配方式分爲如下兩種:jvm

  1. 指針碰撞,這種分配方式創建在堆內已用空間和剩餘空間是完整的,這樣的話,在二者之間放置一個指針做爲分界點的指示器便可,在分配空間時,只須要移到一下指針位置就行了。
  2. 空閒列表,若是 JVM 內的空間不是規整的,那麼就只能採用此方案了。此時 JVM 會維護一個列表,記錄了哪些內存塊是可用的,在分配的時候劃一個大小足夠的區域給對象實例,並更新列表便可。

以上兩種方式採起哪一種,取決於 Java 堆是否工整,而堆是否工整又取決於垃圾回收算法是否具備整理功能。佈局

對象模型

前面說到對象在建立時就已經肯定了內存大小,那麼 JVM 是怎麼肯定對象的大小呢?對象在內存中又是如何存儲的呢?學習

在 JVM 中 Java 的對象模型分爲如下3塊,對象頭實例數據對齊填充,下面就讓咱們來分別介紹一下。線程

對象頭

對象頭的數據包括兩部分。一部分是用於存儲自身運行時數據,這部分數據被官方稱爲「Mark World」。其中存儲數據包括Hashcode、GC 分代年齡、鎖狀態標誌、線程持有鎖、偏向線程ID、偏向時間戳等等指針

對象頭的另一部分是 類型指針,即對象指向其類元數據的指針。經過這個指針,咱們就能夠知道該實例屬於哪一個類。code

實例數據

實例數據就是對象真正存儲的有效信息,也就是代碼中定義的各類類型的字段內容,不管是父類的仍是子類的,都須要記錄下來。其存儲順序受到虛擬機分配策略和定義順序影響。對象

對齊填充

對象填充不是必要數據。在模型中只是起到佔位符的做用。由於 HotSpot 要求對象起始地址必須是8的整數倍,這樣在實例數據達不到要求的時候,就須要經過對齊填充來補齊。blog

對象訪問

對象訪問的方式是經過引用來定位、訪問。但 JVM 規範並無強制要求該經過何種方式使用引用,所以具體實現仍是要依賴與具體虛擬機類型。

不過目前的主流訪問方式就是如下兩種。

  1. 使用引用。其在 Java 堆中會獨立建立一個句柄池,引用指向句柄,而句柄指向實例數據和類型數據。
    使用句柄訪問

使用這種方式來訪問的優勢是穩定,例如在 GC 後,實例數據須要移動,那麼只須要修改句柄池中的內容便可,reference 指向的是穩定的位置,缺點是這種方式須要二次定位,速度較慢。

  1. 直接指針訪問,引用直接堆中對象地址,堆中保存了實例數據和類型數據指針,指針直接指向另外存儲的類型數據。
    經過直接指針訪問對象

使用這種方式的優勢是訪問實例數據快,由於 reference 指向直接的對象,省去了一次內存定位開銷。但缺點就是不夠穩定,在對象移動後,reference 也須要修改值。

具體採用何種,不一樣的虛擬機有不一樣的實現,由於二者各有千秋,並無強烈的優缺點,所以不一樣狀況不一樣處理便可。

總結

在本文中介紹了對象的本質模型是什麼,以及對象是如何建立和訪問使用的,與上文的 JVM 內存模型結合來看,可讓咱們瞭解內存泄露產生的緣由,有助於高效地理解使用 Java 的自動內存管理機制。

iceWang公衆號

文章在公衆號「iceWang」第一手更新,有興趣的朋友能夠關注公衆號,第一時間看到筆者分享的各項知識點。謝謝!筆芯!

本系列文章主要借鑑自《深刻分析 Java Web 技術內幕》和《深刻理解 Java 虛擬機-JVM 高級特性與最佳實踐》。 ​

相關文章
相關標籤/搜索