虛擬機:Java HotSpot(TM) 64-Bit Server VM (25.221-b11, mixed mode)
對象的內存以字節為單位,必須是8的倍數,它的構成由3部分組成:對象頭+實例數據+對齊內存。對象頭主要包括對象的運行行元數據,比較哈希碼、GC分代年齡、鎖狀態標志還有類型指針,類型指針指向類元數據,表明該對象所屬類型。實例數據包括自身數據和所有父級數據,所有父級占內存大小都是8的倍數,沒有就需要補齊。類型指針一般為4字節,在關閉壓縮普通對象指針時(-XX:+UseCompressedOops)為8字節,UseCompressedOops默認是開啟的,只有虛擬機內存達到32G以上,4個字節已經無法滿足尋址需求時,才需要關閉該參數。
普通對象頭除類型指針外的大小為8字節,在開啟壓縮總大小為12字節,不開啟壓縮總大小為16字節;數組對象頭在開啟壓縮時是16字節,不開啟壓縮為24字節。
各種類型大小如下:
對象類型 | 字節 | |
boolean | 1 | |
byte | 1 | |
short | 2 | |
char | 2 | |
int | 4 | |
float | 4 | |
long | 8 | |
double | 8 | |
引用類型 | 開啟指針壓縮為4,不開啟為8 | |
普通對象頭 | 開啟指針壓縮為12,不開啟為8 | |
數據對象頭 | 開啟指針壓縮為16,不開啟為24 |
例1:
public class Persion { int id; }
開啟壓縮普通對象指針時,對象大小:(8+4)+4+0=16字節,補齊0字節
關閉壓縮普通對象指針時,對象大小:(8+8)+4+4=24字節,補齊4字節
例2:
public class Persion { int id; String name; int age; Date birthday; }
開啟壓縮普通對象指針時,對象大小:(8+4)+(4+4+4+4)+4=32字節,補齊了4字節。
關閉壓縮普通對象指針時,對象大小:(8+8)+(4+8+4+8)+0=40字節,補齊了0字節
例3:
public class Persion { int id; String name; int age; Date birthday; boolean school; } public class Student extends Persion { int b; }
開啟壓縮普通對象指針時:
Person對象的大小為:(8+4)+(4+4+4+4+1)+7=32字節,補齊了7字節。
Student對象的大小為:(8+4)+(4+(4+4+4+4+1+7)) +0=40字節,Person對象補齊了7字節。
關閉壓縮普通對象指針時:
Person對象的大小為:(8+8)+(4+8+4+8+1)+7=48字節,補齊7字節
Student對象的大小為:(8+8)+(4+(4+8+4+8+1+7))+4=56字節,Person對象補齊了7字節,Student補齊4字節。
例4:
class MyList { Persion[] elementData = new Persion[10]; }
開啟壓縮普通對象指針時:
MyList對象大小:(8+4)+4+0=16字節,補齊了0字節
new Person[10]數組對象大小:16+4*10+0=56字節,補齊了0字節
關閉壓縮普通對象指針時:
MyList對象大小:(8+8)+8+0=24字節,補齊了0字節
new Person[10]數組對象大小:24+8*10+0=104字節,補齊了0字節
例5:
@SuppressWarnings("serial") class MyArrayList extends ArrayList<Persion> { }
AarryList和它父級只有3個非靜態成員變量(size為整數、elementData為數組引用,在ArrayList類中,modCount為整數在AbstractList類中),靜態變量內存在堆的另外部分,不在對象內。
開啟壓縮普通對象指針時:
MyArrayList對象大小:(8+4)+(0+(4+4+(4+4)))+4=32字節,AbstractList做了一次補齊,整體做了一次補齊。(與下圖結果不符,后面抽時間在看看)
關閉壓縮普通對象指針時:
MyArrayList對象大小:(8+8)+(0+(4+8+(4+4)+4))+0=40字節,AbstractList做了一次補齊,ArrayList做了一次補齊