Java Object obj = new Object()到底占用多少個位元組?
Java中沒有類似C的
sizeof
的操作符,如何擷取一個對象實際占用的位元組數呢?
方法一:
有一種比較友善的方式是通過啟動jdk自帶的jvisualvm來觀察。
先寫一個測試類
public class TestObjSize {
//定義一個直接繼承Object的類,用于觀察
public static class TestObject {
}
public static void main(String[] args) {
List<TestObject> list = new ArrayList<TestObject>(1024);
for(int i=0;i<1000;i++) {
//建立1000個對象,避免被回收,add到list裡面
list.add(new TestObject());
}
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}
編譯運作
#編譯
javac -encoding utf8 TestObjSize.java
#運作
java TestObjSize
jvisualvm觀察
到jdk安裝目錄bin檔案夾下找到jvisualvm.exe啟動後,檢視1000個TestObject的對象占用多少位元組:
可以看到,1000個對象占用了16000個位元組,顯然1個對象占用16個位元組。
補充
既然一個Object對象占用16個位元組,那這個16個位元組中分别存放的是什麼内容呢?
- 前面8個位元組是對象頭,也叫markword,記錄對象被上鎖的各種狀态(鎖更新)和垃圾回收相關資訊等。
- 接下來4個位元組(4G堆記憶體以下;或者32G以内,并且開啟了ClassPointer指針壓縮,否則是8個位元組)是一個指向對象所屬Class對象的指針。
- 接下來4個位元組是為了8位元組對齊而填充的padding。
檢視是否開啟指針壓縮:
java -XX:+PrintFlagsFinal | find "UseCompressed"
----
bool UseCompressedClassPointers := true {lp64_product}
bool UseCompressedOops := true {lp64_product}
UseCompressedClassPointers:類對象指針壓縮選項。
UseCompressedOops(oops–Ordinary Object Pointers):普通對象指針壓縮選項。
方法二
使用OpenJDK提供的jol(Java Object Layout)庫進行觀察。
Maven引入依賴:
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
測試代碼:
Object o = new Object();
String layout = ClassLayout.parseInstance(o).toPrintable();
System.out.println(layout);
輸出:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
解釋:執行個體對象占用16個位元組。
附圖: