1. 程式人生 > 其它 >Java 物件佔用記憶體大小——轉自java404

Java 物件佔用記憶體大小——轉自java404

Java 物件佔用記憶體大小

Java 物件

如果想要了解java物件在記憶體中的大小,必須先要了解java物件的結構。

HotSpot虛擬機器中,物件在記憶體中儲存的佈局可以分為三塊區域:物件頭(Header)、例項資料(Instance Data)和對齊填充(Padding)

java 物件頭

  • Mark Word

HotSpot虛擬機器的物件頭(Object Header)包括兩部分資訊,第一部分用於儲存物件自身的執行時資料, 如雜湊值(HashCode)、GC分代年齡、鎖狀態標誌、執行緒持有的鎖、偏向執行緒ID、偏向時間戳等等,這部分資料的長度在32位和64位的虛擬機器(暫 不考慮開啟壓縮指標的場景)中分別為32個和64個Bits,官方稱它為“Mark Word”。

  • Class Metadata Address

儲存該物件的 Class 物件的地址。就是該物件屬於那個Class。

  • ArrayList

儲存陣列的長度。 如果是陣列物件才會有此資料。非陣列物件沒有此資料。

具體物件頭佔用的大小如下:

長度內容說明
32/64 bit Mark Word 儲存物件的
hashCode
或鎖資訊等
32/64 bit Class
Metadata
Address
儲存到物件
型別資料的
指標
32/64 bit ArrayList 陣列的長度
(如果當前對
象是陣列)

從上面表格中,我們可以推斷出:

32位系統:

  • 物件頭佔用:
    32+32=64bit。
    64bit/8=8byte。

  • 陣列物件頭佔用:
    32+32+32=96bit。
    96bit/8=12byte。

64位系統:

  • 物件頭佔用:
    64+64=128bit。
    128bit/8=16byte。

  • 陣列物件頭佔用:
    64+64+64=192bit。
    192bit/8=24byte。

例項資料

例項資料就是,物件中的例項變數。 例項變數型別分為:基本型別和引用型別。

型別32位系統佔用空間64位系統佔用空間
boolean 1 byte 1 byte
byte 1 byte 1 byte
char 2 byte 2 byte
short 2 byte 2 byte
int 4 byte 4 byte
float 4 byte 4 byte
long 8 byte 8 byte
double 8 byte 8 byte
ref 4 byte 8 byte

對齊填充

物件在堆中分配的最新儲存單位是8byte。如果儲存的資料不夠8byte的倍數,則對齊填充夠8的倍數個位元組。

Java 物件大小分析

下面我們以 64 位的 JDK 進行分析 Java 物件在堆中的佔用空間大小

程式碼示例一

  1. public class StrObj1 {

  2. private String a;

  3. }

  4. public class StrObj2 {

  5. private String a;

  6. private String b;

  7. }

  8. public class StrObj3 {

  9. private String a;

  10. private String b;

  11. private String c;

  12. }

  13. public class StrObj4 {

  14. private String a;

  15. private String b;

  16. private String c;

  17. private String d;

  18. }

  19. public class NumObj {

  20. private int a;

  21. private int b;

  22. private int c;

  23. private int d;

  24. }

  25. public class Obj {

  26. public static void main(String[] args) {

  27. Obj obj = new Obj();

  28. StrObj1 s1 = new StrObj1();

  29. StrObj2 s2 = new StrObj2();

  30. StrObj3 s3 = new StrObj3();

  31. StrObj4 s4 = new StrObj4();

  32. Obj[] arrObj = new Obj[10];

  33. NumObj num = new NumObj();

  34. //System.gc() 會出發 FullGC。

  35. System.gc();

  36. }

  37. }

執行程式

java -XX:+HeapDumpBeforeFullGC
-XX:HeapDumpPath=D:\hprof\test2.hprof
-XX:-UseCompressedOops
cn.com.infcn.jmat.ObjectAnalyze

啟動引數說明:

-XX:+UseCompressedOops 開啟指標壓縮。(預設開啟,該引數對64位虛擬機器有用) -XX:-UseCompressedOops 關閉指標壓縮。 其它引數具體 JVM 引數解釋詳見:生成 Heap Dump 的幾種方式

因為 System.gc(); 會出發FullGC,配合-XX:+HeapDumpBeforeFullGC 引數,會在 FullGC 前會在生成一個堆dump檔案:D:\hprof\test2.hprof

分析dump

本案例,使用 jmat 工具進行分析 dump 檔案。

cn.com.infcn.jmat.Obj 物件分析

從圖中我們發現 cn.com.infcn.jmat.Obj 物件佔用 16 byte 空間。 非陣列64位的物件頭 佔用16位元組,而且改物件沒有屬性,16位元組正好也是8的倍數,不需要填充,所以佔用堆空間久違16位元組。

cn.com.infcn.jmat.StrObj1

圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 24 byte 空間。

物件頭 16 byte 1 個引用型別例項變數 16 + 8 = 24 byte

cn.com.infcn.jmat.StrObj2

圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 32 byte 空間

物件頭 16 byte 2 個引用型別例項變數 16 + 2 * 8 = 32 byte

cn.com.infcn.jmat.StrObj3

圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 40 byte 空間

物件頭 16 byte 3 個引用型別例項變數 16 + 3 * 8 = 40 byte

cn.com.infcn.jmat.StrObj4

圖中可以看出 cn.com.infcn.jmat.StrObj1 物件佔用 48 byte 空間

物件頭 16 byte 4個引用型別例項變數 16 + 4 * 8 = 48 byte

cn.com.infcn.jmat.NumObj

圖中可以看出 cn.com.infcn.jmat.NumObj 物件佔用 32 byte 空間

4個 int 型別例項變數
16 + 4 * 4 = 32 byte

cn.com.infcn.jmat.Obj[] 陣列

圖中可以看出 cn.com.infcn.jmat.Obj[] 物件佔用 104 byte 空間

陣列物件頭 24 byte 10 個 Obj 的引用。 24 + 8 * 10 = 104 byte

物件陣列中儲存的是物件的引用,而不是實際的資料。

程式碼示例 二

  1. public class BooleanObj1 {

  2. boolean a;

  3. }

  4. ......

  5. public class BooleanObj8 {

  6. boolean a;

  7. boolean b;

  8. boolean c;

  9. boolean d;

  10. boolean e;

  11. boolean f;

  12. boolean g;

  13. boolean h;

  14. }

  15. public class BooleanObj9 {

  16. boolean a;

  17. boolean b;

  18. boolean c;

  19. boolean d;

  20. boolean e;

  21. boolean f;

  22. boolean g;

  23. boolean h;

  24. boolean i;

  25. }

以指標非壓縮方式執行,然後分析dump。

從圖中我們發現 BooleanObj1 和 BooleanObj8 大小一樣都是24。 而 BooleanObj9 的大小為32。

BooleanObj1

物件頭 16 byte 1 個 boolean 例項變數。

16 + 1 = 17 byte。 因為 17 byte 不是 8 的倍數,需要 對齊填充。 所以BooleanObj1 所佔空間為 24 byte。

BooleanObj8

物件頭 16 byte 8 個 boolean 例項變數。

16 + 8 = 24 byte。

BooleanObj9

物件頭 16 byte 9 個 boolean 例項變數

16 + 9 =25 byte對齊填充 後為 32 byte


喜歡本文的朋友們,歡迎長按下圖關注訂閱號java404,收聽更多精彩的內容

原始碼,是痛苦的,又是快樂的,如果沒有這痛苦,也就沒有了這快樂!