在Java中,一個空Object對象的大小是8byte,這個大小隻是儲存堆中一個沒有任何屬性的對象的大小。看下面語句:
- Object ob = new Object();
這樣在程式中完成了一個Java對象的生命,但是它所佔的空間為:4byte+8byte。4byte是上面部分所說的Java棧中儲存引用的所需要的空間。而那8byte則是Java堆中對象的資訊。因為所有的Java非基本類型的對象都需要預設繼承Object對象,因此不論什麼樣的Java對象,其大小都必須是大於8byte。
有了Object對象的大小,我們就可以計算其他對象的大小了。
- Class NewObject {
- int count;
- boolean flag;
- Object ob;
- }
其大小為:Null 物件大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小(4byte)=17byte。但是因為Java在對對象記憶體配置時都是以8的整數倍來分,因此大於17byte的最接近8的整數倍的是24,因此此對象的大小為24byte。
本文中,我們討論一個問題:如何計算(或者說,估算)一個Java對象佔用的記憶體數量?
通常,我們談論的堆記憶體使用量的前提是以“一般情況”為背景的。不包括下面兩種情形:
- 某些情況下,JVM根本就沒有把Object放入堆中。例如:原則上講,一個小的thread-local對象存在於棧中,而不是在堆中。
- 被Object佔用記憶體的大小依賴於Object的目前狀態。例如:Object的同步鎖是否生效,或者,Object是否正在被回收。
我們先來看看在堆中單個的Object長什麼樣子
在堆中,每個對象由四個域構成(A、B、C 和 D),下面我們逐個解釋一下:
- A:對象頭,佔用很少的位元組,表述Object目前狀態的資訊
- B:基本類型域佔用的空間(原生域指 int、boolean、short等)
- C:參考型別域佔用的空間(參考型別域指 其他對象的引用,每個引用佔用4個位元組)
- D:填充物佔用的空間(後面說明什麼是填充物)
下面我們對A、B、C 和 D 逐一解釋
A:對象頭
記憶體中,每個對象佔用的總空間不僅包含對象內聲明的變數所需要的空間,還包括一些額外資訊,比如:對象頭 和 填充物。“對象頭”的作用是用來記錄一個對象的執行個體名字、ID 和 執行個體狀態(例如,當前執行個體是否“可到達”,或者當前鎖的狀態等等)。
在當前的JVM版本中(Hotspot),“對象頭”佔用的位元組數如下:
- 一個普通對象,佔用8 bytes
- 數組,佔用 12 bytes,包含普通對象的 8 bytes + 4 bytes(數組長度)
B:基本類型
boolean、byte 佔用 1 byte,char、short 佔用 2 bytes,int、float 佔用 4 bytes,long、double 佔用 8 bytes
C:參考型別
每個參考型別佔用 4 bytes
D:填充物
在Hotspot中,每個對象佔用的總空間是以8的倍數計算的,對象佔用總空間(對象頭+聲明變數)不足8的倍數時候,自動補齊。而,這些被填充的空間,我們可以稱它為“填充物”。我們看下具體執行個體:
- 一個Null 物件(沒有聲明任何變數)佔用 8 bytes -- > 對象頭 佔用 8 bytes
- 只聲明了一個boolean類型變數的類,佔用 16 bytes --> 對象頭(8 bytes) + boolean (1 bytes) + 填充物(7 bytes)
- 聲明了8個boolean類型變數的類,佔用 16 bytes --> 對象頭(8 bytes) + boolean (1 bytes) * 8
通過上面的執行個體,更有助於我們理解