1. 程式人生 > >Java物件在記憶體中佔用的空間

Java物件在記憶體中佔用的空間

本文主要結合lucene中RamUsageEstimator類來談談Java物件在記憶體中佔用的空間大小。

注意這種計算方式適用於OpenJDK和Oracle JDK兩個版本,其它版本可能有所不同。

從整體來看,java物件由物件頭、例項資料、對齊填充3個部分組成,其中對齊填充是指物件頭的佔用空間與例項資料的佔用空間如果不是8的整數倍,就需要新增pad填滿直到總的佔用空間為8的倍數。這裡暫時說的8的整數倍,因為在lucene原始碼中64位的虛擬機器是動態獲取的(具體原因暫時不清楚,如果像網上和書上說的是固定8的整數倍就沒必要動態獲取了,盡信書不如無書有些東西沒看到原始碼前最好別下定論),32位是固定的8個位元組。物件引用的大小在64位jvm中如果開啟指標壓縮為4個位元組否則8個位元組,在32位jvm中只佔4個位元組。

普通物件的物件頭大小為物件引用的大小加上8位元組,陣列的物件頭等於普通物件頭的大小加上4個位元組的和並且要按照8位元組對齊。

位元組陣列佔用的空間=陣列的物件頭+1*陣列個數的和並且按照8位元組對齊;

boolean陣列的佔用空間與位元組陣列的佔用空間相同;

char陣列的佔用空間=陣列的物件頭+2*陣列個數的和並且按照8位元組對齊;

short陣列的佔用空間與char陣列的佔用空間相同;

int陣列的佔用空間=陣列的物件頭+4*陣列個數的和並且按照8位元組對齊;

float陣列的佔用空間與int陣列的佔用空間相同;

long陣列的佔用空間=陣列的物件頭+8*陣列個數的和並且按照8位元組對齊;

double陣列的佔用空間與long陣列的佔用空間相同;

物件陣列與以上陣列稍有不同,陣列中記錄的是所有物件的引用地址,因此佔用空間=陣列的物件頭+物件引用的大小*陣列個數的和並且按照8位元組對齊後再加上每個物件自身佔用的實際空間;

現在詳細說明每個物件的佔用空間,除了物件頭,其中的例項資料部分(不包括靜態變數)包括基本型別和引用型別(所有的陣列和普通物件都是引用型別)。引用型別的指標大小在上面已經說過,指向真正物件的佔用空間就是現在討論的,實際上這就是一個遞迴,例如:

class Test{

    int a;

   byte[] b=new byte[10];

}

假設在64位jvm中指標壓縮的情況下,Test物件佔用的空間=align(物件頭(4+8)+資料(4+4))+size(b)。注意:所有的引用型別不與本物件在一個連續的地址空間中,所以位元組對齊align時不能包含引用物件的實際大小!

在lucene中為了計算物件實際佔用空間就需要實現Accountable介面,就是因為當物件內部存在一個物件引用時就需要計算引用物件實際佔