java對象內存佈局

咱們知道在Java中基本數據類型的大小,例如int類型佔4個字節、long類型佔8個字節,那麼Integer對象和Long對象會佔用多少內存呢?本文介紹一下Java對象在堆中的內存結構以及對象大小的計算。數組

對象的內存佈局

一個Java對象在內存中包括對象頭、實例數據和補齊填充3個部分:佈局

 

對象頭

  • Mark Word:包含一系列的標記位,好比輕量級鎖的標記位,偏向鎖標記位等等。在32位系統佔4字節,在64位系統中佔8字節;
  • Class Pointer:用來指向對象對應的Class對象(其對應的元數據對象)的內存地址。在32位系統佔4字節,在64位系統中佔8字節;
  • Length:若是是數組對象,還有一個保存數組長度的空間,佔4個字節;

對象實際數據

對象實際數據包括了對象的全部成員變量,其大小由各個成員變量的大小決定,好比:byte和boolean是1個字節,short和char是2個字節,int和float是4個字節,long和double是8個字節,reference是4個字節(64位系統中是8個字節)。優化

Primitive Type Memory Required(bytes)
boolean 1
byte 1
short 2
char 2
int 4
float 4
long 8
double 8

對於reference類型來講,在32位系統上佔用4bytes, 在64位系統上佔用8bytes。ui

對齊填充

Java對象佔用空間是8字節對齊的,即全部Java對象佔用bytes數必須是8的倍數。例如,一個包含兩個屬性的對象:int和byte,這個對象須要佔用8+4+1=13個字節,這時就須要加上大小爲3字節的padding進行8字節對齊,最終佔用大小爲16個字節。spa

注意:以上對64位操做系統的描述是未開啓指針壓縮的狀況,關於指針壓縮會在下文中介紹。操作系統

對象頭佔用空間大小

這裏說明一下32位系統和64位系統中對象所佔用內存空間的大小:3d

  • 在32位系統下,存放Class Pointer的空間大小是4字節,MarkWord是4字節,對象頭爲8字節;
  • 在64位系統下,存放Class Pointer的空間大小是8字節,MarkWord是8字節,對象頭爲16字節;
  • 64位開啓指針壓縮的狀況下,存放Class Pointer的空間大小是4字節,MarkWord是8字節,對象頭爲12字節;
  • 若是是數組對象,對象頭的大小爲:數組對象頭8字節+數組長度4字節+對齊4字節=16字節。其中對象引用佔4字節(未開啓指針壓縮的64位爲8字節),數組MarkWord爲4字節(64位未開啓指針壓縮的爲8字節);
  • 靜態屬性不算在對象大小內。

指針壓縮

從上文的分析中能夠看到,64位JVM消耗的內存會比32位的要多大約1.5倍,這是由於對象指針在64位JVM下有更寬的尋址。對於那些將要從32位平臺移植到64位的應用來講,平白無辜多了1/2的內存佔用,這是開發者不肯意看到的。指針

從JDK 1.6 update14開始,64位的JVM正式支持了 -XX:+UseCompressedOops 這個能夠壓縮指針,起到節約內存佔用的新參數。code

什麼是OOP?

OOP的全稱爲:Ordinary Object Pointer,就是普通對象指針。啓用CompressOops後,會壓縮的對象:對象

  • 每一個Class的屬性指針(靜態成員變量);
  • 每一個對象的屬性指針;
  • 普通對象數組的每一個元素指針。

固然,壓縮也不是全部的指針都會壓縮,對一些特殊類型的指針,JVM是不會優化的,例如指向PermGen的Class對象指針、本地變量、堆棧元素、入參、返回值和NULL指針不會被壓縮。

啓用指針壓縮

在Java程序啓動時增長JVM參數:-XX:+UseCompressedOops來啓用。

注意:32位HotSpot VM是不支持UseCompressedOops參數的,只有64位HotSpot VM才支持。

本文中使用的是JDK 1.8,默認該參數就是開啓的。

相關文章
相關標籤/搜索