Java 內存空間佔用規則分析

 

一個對象實例佔用了多少字節,消耗了多少內存?這樣的問題在c或c++裏使用sizeof()方法就能夠獲得明確答案,在java裏好像沒有這樣的方法(java同樣能夠實現),不過經過jmap工具卻是能夠查看出一個對象的佔用內存的大小,這裏介紹一種經過分析java代碼計算內存使用狀況的方法。java

注意,一下討論的狀況都是基於32位機,不適用用64位機,JVM是sun的HotSpot,不一樣的虛擬機實現可能會不一樣c++

 

規則一:每一個對象被按照8bytes粒度對齊(數組除外)數組

 

在jvm中每一個對象(數組除外)都有一個頭,這個頭有兩個字,第一個字存儲的時對象的一些標誌位信息,例如:鎖標誌位、經歷了幾回gc等信息,第二個字是一個引用,指向了這個類的類信息。這裏jvm給這兩個字留了8個字節的空間(這個爲啥用8個字節空間不是很清楚,一個字即兩個字節,我一直認爲4個字節就夠了)jvm

按規則一:new Object();這個Object實例就佔用了8個字節工具

 

規則二:爲類屬性分配存儲空間時不是按照類中定義的屬性順序,而是按以下的順序:對象

            一、double\long;----8bytes繼承

            二、int\float;----4bytes內存

            三、char\short;----2bytes虛擬機

            四、boolean\byte;----1bytesclass

            五、reference;----4bytes

例如:

Java代碼  

public class A {   

    byte a;   

    char b;   

    int c;   

    long d;   

    Object e;   

}   

 

 

 

屬性        須要字節數        累積字節數

header        8bytes        8

long:d        8bytes        16

int:c        4bytes        20

char:b        2bytes        22

byte:a        1bytes        23

Object:e        4bytes        27

         padding 5bytes        32 

 

最後一行padding 5bytes的目的是,規則一中描述每一個對象按照8個字節的粒度對齊,這樣下一個分配的對象的開始位置必須在8的倍數上,而離27最近的8的倍數是32,所以加了5bytes。A佔用32bytes

能夠用jmap看一下這個計算是否準確

 

規則三:對於繼承時,要按照規則二先計算父類的類屬性佔用狀況,再按照規則二計算子類的類屬性佔用狀況,不能將父類和子類的屬性混合在一塊兒按規則二分配。

例如:

Java代碼  

class B{  

    long a;  

    int b;  

    int c;  

}  

 

class BB extends B{  

    long d;  

}  

 

 屬性        佔用字節數        累計字節數

header        8        8

a        8        16

b        4        20

c        4        24

d        8        32

 

這裏累計字節正好是8的倍數,知足規則一,所以不用padding字節。BB對象內存佔用了32bytes

 

規則四:父類的最後一個屬性和子類第一個屬性必須按4個字節的倍數對齊

例如:

Java代碼  

class B{  

    long a;  

    int b;  

    char c;  

}  

 

class BB extends B{  

    long d;  

}  

 

 

屬性        佔用的字節        累計字節

head        8        8

a        8        16

c        2        18

         padding 2        20

d        8        28

         padding 4        32

 

第一次padding2是由於屬性c分配內存後,不知足父類最後一個屬性和子類第一個屬性按4字節粒度對齊(18除4除不開),所以須要添加兩個字節使其能夠按4字節粒度對齊。

第二次paadding4是依據規則一

 

規則五:當子類的第一個屬性是double或long,可是父類不能按8字節粒度對齊時,子類內存分配時的順序將不按規則二進行,而是按:先int\float、char\short、boolean\byte、reference、long\double

 

例如:

Java代碼  

class A{  

    byte a;  

}  

 

class B extends A{  

    long b;  

    short c;  

    byte d;  

}  

 

 

屬性        佔用字節數        累計佔用字節數

head        8        8

a        1        9

         padding 3        12

c        2        14

d        1        15

         padding 1        16

b        8        24

 第一次 padding 3是根據規則四

 第二次 padding 1是由於b屬性是8個字節,所以須要按8個字節粒度對齊。B佔用24bytes

 

 對於數組,與普通對象不一樣的是在頭部,頭部多了4個字節用於存儲長度信息。所以數組的head是12bytes而不是8bytes

相關文章
相關標籤/搜索