java的對象物理結構,以及對象頭中MarkWord與鎖的關係

關於鎖升級可參看 https://blog.csdn.net/u013378306/article/details/106538659

java 對象頭

我們都知道,Java對象存儲在堆(Heap)內存。那麼一個Java對象到底包含什麼呢?概括起來分爲對象頭、對象體和對齊字節。如下圖所示:

對象的幾個部分的作用:

1.對象頭中的Mark Word(標記字)主要用來表示對象的線程鎖狀態,另外還可以用來配合GC、存放該對象的hashCode;

2.Klass Word是一個指向方法區中Class信息的指針,意味着該對象可隨時知道自己是哪個Class的實例;

3.數組長度也是佔用64位(8字節)的空間,這是可選的,只有當本對象是一個數組對象時纔會有這個部分;

4.對象體是用於保存對象屬性和值的主體部分,佔用內存空間取決於對象的屬性數量和類型;

5.對齊字是爲了減少堆內存的碎片空間(不一定準確)。

瞭解了對象的總體結構,接下來深入地瞭解對象頭的三個部分。

 

一、Mark Word(標記字)

 

以上是Java對象處於5種不同狀態時,Mark Word中64個位的表現形式,上面每一行代表對象處於某種狀態時的樣子。其中各部分的含義如下:

lock:2位的鎖狀態標記位,由於希望用盡可能少的二進制位表示儘可能多的信息,所以設置了lock標記。該標記的值不同,整個Mark Word表示的含義不同。biased_lock和lock一起,表達的鎖狀態含義如下:

biased_lock:對象是否啓用偏向鎖標記,只佔1個二進制位。爲1時表示對象啓用偏向鎖,爲0時表示對象沒有偏向鎖。lock和biased_lock共同表示對象處於什麼鎖狀態。

age:4位的Java對象年齡。在GC中,如果對象在Survivor區複製一次,年齡增加1。當對象達到設定的閾值時,將會晉升到老年代。默認情況下,並行GC的年齡閾值爲15,併發GC的年齡閾值爲6。由於age只有4位,所以最大值爲15,這就是-XX:MaxTenuringThreshold選項最大值爲15的原因。

identity_hashcode:31位的對象標識hashCode,採用延遲加載技術。調用方法System.identityHashCode()計算,並會將結果寫到該對象頭中。當對象加鎖後(偏向、輕量級、重量級),MarkWord的字節沒有足夠的空間保存hashCode,因此該值會移動到管程Monitor中。

thread:持有偏向鎖的線程ID。

epoch:偏向鎖的時間戳。

ptr_to_lock_record:輕量級鎖狀態下,指向棧中鎖記錄的指針。

ptr_to_heavyweight_monitor:重量級鎖狀態下,指向對象監視器Monitor的指針。

  


二、Klass Word(類指針)


這一部分用於存儲對象的類型指針,該指針指向它的類元數據,JVM通過這個指針確定對象是哪個類的實例。該指針的位長度爲JVM的一個字大小,即32位的JVM爲32位,64位的JVM爲64位。
如果應用的對象過多,使用64位的指針將浪費大量內存,統計而言,64位的JVM將會比32位的JVM多耗費50%的內存。爲了節約內存可以使用選項+UseCompressedOops開啓指針壓縮,其中,oop即ordinary object pointer普通對象指針。開啓該選項後,下列指針將壓縮至32位:

每個Class的屬性指針(即靜態變量)
每個對象的屬性指針(即對象變量)
普通對象數組的每個元素指針
當然,也不是所有的指針都會壓縮,一些特殊類型的指針JVM不會優化,比如指向PermGen的Class對象指針(JDK8中指向元空間的Class對象指針)、本地變量、堆棧元素、入參、返回值和NULL指針等。


三、數組長度


 如果對象是一個數組,那麼對象頭還需要有額外的空間用於存儲數組的長度,這部分數據的長度也隨着JVM架構的不同而不同:32位的JVM上,長度爲32位;64位JVM則爲64位。64位JVM如果開啓+UseCompressedOops選項,該區域長度也將由64位壓縮至32位。
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章