Java 物件佔用記憶體大小——轉自java404
Java 物件佔用記憶體大小
Java 物件
如果想要了解java物件在記憶體中的大小,必須先要了解java物件的結構。
HotSpot虛擬機器中,物件在記憶體中儲存的佈局可以分為三塊區域:物件頭(Header)、例項資料(Instance Data)和對齊填充(Padding)
java 物件頭
-
Mark Word
HotSpot虛擬機器的物件頭(Object Header)包括兩部分資訊,第一部分用於儲存物件自身的執行時資料, 如雜湊值(HashCode)、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒ID、偏向時間戳等等,這部分資料的長度在32位和64位的虛擬機器(暫 不考慮開啟壓縮指標的場景)中分別為32個和64個Bits,官方稱它為“Mark Word”。
-
Class Metadata Address
儲存該物件的 Class 物件的地址。就是該物件屬於那個Class。
-
ArrayList
儲存陣列的長度。 如果是陣列物件才會有此資料。非陣列物件沒有此資料。
具體物件頭佔用的大小如下:
長度 | 內容 | 說明 |
---|---|---|
32/64 bit | Mark Word | 儲存物件的 hashCode 或鎖資訊等 |
32/64 bit | Class Metadata Address |
儲存到物件 型別資料的 指標 |
32/64 bit | ArrayList | 陣列的長度 (如果當前對 象是陣列) |
從上面表格中,我們可以推斷出:
32位系統:
-
物件頭佔用:
32+32=64bit。
64bit/8=8byte。 -
陣列物件頭佔用:
32+32+32=96bit。
96bit/8=12byte。
64位系統:
-
物件頭佔用:
64+64=128bit。
128bit/8=16byte。 -
陣列物件頭佔用:
64+64+64=192bit。
192bit/8=24byte。
例項資料
例項資料就是,物件中的例項變數。 例項變數型別分為:基本型別和引用型別。
型別 | 32位系統佔用空間 | 64位系統佔用空間 |
---|---|---|
boolean | 1 byte | 1 byte |
byte | 1 byte | 1 byte |
char | 2 byte | 2 byte |
short | 2 byte | 2 byte |
int | 4 byte | 4 byte |
float | 4 byte | 4 byte |
long | 8 byte | 8 byte |
double | 8 byte | 8 byte |
ref | 4 byte | 8 byte |
對齊填充
物件在堆中分配的最新儲存單位是8byte。如果儲存的資料不夠8byte的倍數,則對齊填充夠8的倍數個位元組。
Java 物件大小分析
下面我們以 64 位的 JDK 進行分析 Java 物件在堆中的佔用空間大小
程式碼示例一
-
public class StrObj1 {
-
private String a;
-
}
-
public class StrObj2 {
-
private String a;
-
private String b;
-
}
-
public class StrObj3 {
-
private String a;
-
private String b;
-
private String c;
-
}
-
public class StrObj4 {
-
private String a;
-
private String b;
-
private String c;
-
private String d;
-
}
-
public class NumObj {
-
private int a;
-
private int b;
-
private int c;
-
private int d;
-
}
-
public class Obj {
-
public static void main(String[] args) {
-
Obj obj = new Obj();
-
StrObj1 s1 = new StrObj1();
-
StrObj2 s2 = new StrObj2();
-
StrObj3 s3 = new StrObj3();
-
StrObj4 s4 = new StrObj4();
-
Obj[] arrObj = new Obj[10];
-
NumObj num = new NumObj();
-
//System.gc() 會出發 FullGC。
-
System.gc();
-
}
-
}
執行程式
java -XX:+HeapDumpBeforeFullGC
-XX:HeapDumpPath=D:\hprof\test2.hprof
-XX:-UseCompressedOops
cn.com.infcn.jmat.ObjectAnalyze
啟動引數說明:
-XX:+UseCompressedOops 開啟指標壓縮。(預設開啟,該引數對64位虛擬機器有用) -XX:-UseCompressedOops 關閉指標壓縮。 其它引數具體 JVM 引數解釋詳見:生成 Heap Dump 的幾種方式
因為 System.gc(); 會出發FullGC,配合-XX:+HeapDumpBeforeFullGC 引數,會在 FullGC 前會在生成一個堆dump檔案:D:\hprof\test2.hprof
分析dump
本案例,使用 jmat 工具進行分析 dump 檔案。
cn.com.infcn.jmat.Obj 物件分析
從圖中我們發現 cn.com.infcn.jmat.Obj 物件佔用 16 byte 空間。 非陣列64位的物件頭 佔用16位元組,而且改物件沒有屬性,16位元組正好也是8的倍數,不需要填充,所以佔用堆空間久違16位元組。
cn.com.infcn.jmat.StrObj1
圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 24 byte 空間。
物件頭 16 byte 1 個引用型別例項變數 16 + 8 = 24 byte
cn.com.infcn.jmat.StrObj2
圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 32 byte 空間
物件頭 16 byte 2 個引用型別例項變數 16 + 2 * 8 = 32 byte
cn.com.infcn.jmat.StrObj3
圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 40 byte 空間
物件頭 16 byte 3 個引用型別例項變數 16 + 3 * 8 = 40 byte
cn.com.infcn.jmat.StrObj4
圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 48 byte 空間
物件頭 16 byte 4個引用型別例項變數 16 + 4 * 8 = 48 byte
cn.com.infcn.jmat.NumObj
圖中可以看出 cn.com.infcn.jmat.NumObj 物件佔用 32 byte 空間
4個 int 型別例項變數
16 + 4 * 4 = 32 byte
cn.com.infcn.jmat.Obj[] 陣列
圖中可以看出 cn.com.infcn.jmat.Obj[] 物件佔用 104 byte 空間
陣列物件頭 24 byte 10 個 Obj 的引用。 24 + 8 * 10 = 104 byte
物件陣列中儲存的是物件的引用,而不是實際的資料。
程式碼示例 二
-
public class BooleanObj1 {
-
boolean a;
-
}
-
......
-
public class BooleanObj8 {
-
boolean a;
-
boolean b;
-
boolean c;
-
boolean d;
-
boolean e;
-
boolean f;
-
boolean g;
-
boolean h;
-
}
-
public class BooleanObj9 {
-
boolean a;
-
boolean b;
-
boolean c;
-
boolean d;
-
boolean e;
-
boolean f;
-
boolean g;
-
boolean h;
-
boolean i;
-
}
以指標非壓縮方式執行,然後分析dump。
從圖中我們發現 BooleanObj1 和 BooleanObj8 大小一樣都是24。 而 BooleanObj9 的大小為32。
BooleanObj1
物件頭 16 byte 1 個 boolean 例項變數。
16 + 1 = 17 byte。 因為 17 byte 不是 8 的倍數,需要 對齊填充。 所以BooleanObj1 所佔空間為 24 byte。
BooleanObj8
物件頭 16 byte 8 個 boolean 例項變數。
16 + 8 = 24 byte。
BooleanObj9
物件頭 16 byte 9 個 boolean 例項變數
16 + 9 =25 byte對齊填充 後為 32 byte
喜歡本文的朋友們,歡迎長按下圖關注訂閱號java404,收聽更多精彩的內容
原始碼,是痛苦的,又是快樂的,如果沒有這痛苦,也就沒有了這快樂!