如何計算Java物件佔用了多少空間?

WsztRush發表於2016-01-09

在Java中沒有sizeof運算子,所以沒辦法知道一個物件到底佔用了多大的空間,但是在分配物件的時候會有一些基本的規則,我們根據這些規則大致能判斷出來物件大小。

物件頭

物件的頭部至少有兩個WORD,如果是陣列的話,那麼三個WORD,內容如下:

  1. 物件的HashCode,鎖資訊等
  2. 到物件型別資料的指標
  3. 陣列的長度(如果是陣列的話)

規則

首先,任何物件都是8位元組對齊,屬性按照[long,double]、[int,float]、[char,short]、[byte,boolean]、reference的順序存放,舉個例子:

public class Test {
    byte a;
    int b;
    boolean c;
    long d;
    Object e;
}

如果這個物件的屬性按照順序存放的話,要佔用的空間為:head(8) + a(1) + padding(3) + b(4) + c(1) + padding(7) + d(8) + e(4) + padding(4) = 40。但是按照這個規則得到:head(8) + d(8) + b(4) + a(1) + c(1) + padding(2) + e(4) + padding(4) = 32。可以看到節省了不少空間。

在涉及繼承關係的時候有一個最基本的規則:首先存放父類中的成員,接著才是子類中的成員,舉個例子:

class A {
    long a;
    int b;
    int c;
}
class B extends A {
    long d;
}

這樣存放的順序及佔用空間如下:head(8) + a(8) + b(4) + c(4) + d(8) = 32。那如果父類中的屬性不夠八個位元組怎麼辦?這樣就有了新的一條規則:父類中最後一個成員與子類的第一個成員的間隔如果不夠4個位元組,此時需要擴充套件到4個位元組的基本單位,舉個例子:

class A {
    byte a;
}
class B extends A {
    byte b;
}

那麼此時佔用的空間如下:head(8) + a(1) + padding(3) + b(1) + padding(3) = 16。顯然這種方式比較浪費空間,那麼就有了:如果子類的第一個成員是double或者long,並且父類並沒有用完8個位元組,JVM會破壞規將較小的資料填充到該空間,舉個例子:

class A {
    byte a;
}
class B extends A {
    long b;
    short c;
    byte d;
}

此時佔用的空間如下:head(8) + a(1) + padding(3) + c(2) + d(1) + padding(1) + b(8) = 24。

相關文章