原生類型(primitive type)的內存占用如下:
Primitive Type Memory Required(bytes) boolean 1 byte 1 short 2 char 2 int 4 float 4 long 8 double 8 引用類型(reference type: Integer)在 32 位系統上每個占用 4bytes(即32bit, 才能管理 2^32=4G 的內存), 在 64 位系統上每個占用 8bytes(開啟壓縮為 4 bytes)。 四. 對齊填充 HotSpot 的對齊方式為 8 字節對齊,不足的需要 Padding 填充對齊, 公式:(對象頭 + 實例數據 + padding)% 8 == 0 (0<= padding <8) 五. 計算 Java 對象占用空間大小 借助 Instrument 接口的 getObjectSize 方法計算對象占用空間SizeOfAgent: 計算對象大小類
package com.wenniuwuren.objectsizeof; import java.lang.instrument.Instrumentation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.IdentityHashMap; import java.util.Map; import java.util.Stack; /** * 借助 Instrumentation 接口的 getObjectSize 方法計算對象占用空間 * 原來的 sizeOf 只能計算本對象占用空間, 無法計算繼承下來的占用空間, * 不過可以用反射的方法把全部占用空間計算出來 * * Created by zhuyb on 16/3/20. */ public class SizeOfAgent { static Instrumentation instrumentation; // 第一個參數由 –javaagent, 第二個參數由 JVM 傳入 public static void premain(String agentArgs, Instrumentation instP) { instrumentation = instP; } // 返回沒有子類對象大小的大小 public static long sizeOf(Object o) { if (instrumentation == null) { throw new IllegalStateException("Can not access instrumentation environment.\n" + "Please check if jar file containing SizeOfAgent class is \n" + "specified in the java's \"-javaagent\" command line argument."); } return instrumentation.getObjectSize(o); } /** * * 計算復合對象 * @param obj object to calculate size of * @return object size */ public static long fullSizeOf(Object obj) { Map使用上述代碼必須將上述代碼打成 jar 包, 並且 MANIFEST.MF 文件設置參數( Premain-Class:sizeof.agent.SizeOfAgent Boot-Class-Path:
maven-jar-plugin 2.4 SizeOfAgent false com.wenniuwuren.objectsizeof.SizeOfAgentfalse
package com.wenniuwuren.objectsizeof; import static com.wenniuwuren.objectsizeof.SizeOfAgent.*; /** * 以下結果在 64-bit JVM 下測試 * 啟動參數1(不壓縮指針長度):-javaagent:target/SizeOfAgent.jar -XX:-UseCompressedOops * * Created by zhuyb on 16/3/20. */ public class SizeOfAgentTest { public static void main(String[] args) { System.out.println("------------------空對象----------------------------"); // 16 bytes + 0 + 0 = 16 空對象, 只有對象頭 System.out.println("sizeOf(new Object()) = " + sizeOf(new Object())); System.out.println("fullSizeOf(new Object()) = " + fullSizeOf(new Object())); System.out.println("----------------非空對象含有原始類型、引用類型------------------------------"); // 16 bytes + 8 + 4 + padding = 32 System.out.println("sizeOf(new A()) = " + sizeOf(new A())); System.out.println("fullSizeOf(new A()) = " + fullSizeOf(new A())); // 16 + 4 + padding =24 數據是一個 int System.out.println("sizeOf(new Integer(1)) = " + sizeOf(new Integer(1))); // (16 + int hash:4 + int hash32:4 + refer char value[]:8 + padding) = 32 // 靜態屬性(static)不計算空間,因為所有對象都是共享一塊空間的 // 不同版本JDK可能 String 內部 Field 可能不同,本次測試使用JDK1.7 System.out.println("sizeOf(new String()) = " + sizeOf(new String())); // (16 + 4 + 4 + 8 + padding) + (24 + 0 + padding) = 56 System.out.println("fullSizeOf(new String()) = " + fullSizeOf(new String())); // (16 + 4 + 4 + 8 + padding) = 32 System.out.println("sizeOf(new String('a')) = " + sizeOf(new String("a"))); // (16 + 4 + 4 + 8 +padding) + (24 + 2 + padding) = 64 System.out.println("fullSizeOf(new String('a')) = " + fullSizeOf(new String("a"))); System.out.println("-------------------原始類型數組對象---------------------------"); // 24 bytes + 0*1 + 0 = 24 數組長度為 0,所以只有對象頭的長度 System.out.println("sizeOf(new byte[0]) = " + sizeOf(new byte[0])); System.out.println("fullSizeOf(new byte[0]) = " + fullSizeOf(new byte[0])); // 24 + 1*1 + padding = 32 System.out.println("sizeOf(new byte[1]) = " + sizeOf(new byte[1])); System.out.println("fullSizeOf(new byte[1]) = " + fullSizeOf(new byte[1])); // 24 + 1*2 + padding = 32 System.out.println("sizeOf(new char[1]) = " + sizeOf(new char[1])); System.out.println("fullSizeOf(new char[1]) = " + fullSizeOf(new char[1])); // 24 + 9*1 + padding = 40 System.out.println("sizeOf(new byte[9]) = " + sizeOf(new byte[9])); System.out.println("fullSizeOf(new byte[9]) = " + fullSizeOf(new byte[9])); System.out.println("--------------------引用類型數組對象--------------------------"); // 24 bytes + 0*8 + 0 = 24 數組長度為 0 System.out.println("sizeOf(new Integer[0]) = " + sizeOf(new Integer[0])); System.out.println("fullSizeOf(new Integer[0]) = " + fullSizeOf(new Integer[0])); // 24 bytes + 1*8 + 0 = 32 引用對象 64-bit JVM 占用 8 bytes System.out.println("sizeOf(new Integer[1]) = " + sizeOf(new Integer[1])); System.out.println("fullSizeOf(new Integer[1]) = " + fullSizeOf(new Integer[1])); // 24 bytes + 2*8 + padding = 40 System.out.println("sizeOf(new Integer[1]) = " + sizeOf(new Integer[1])); System.out.println("fullSizeOf(new Integer[1]) = " + fullSizeOf(new Integer[1])); // 24 + 3*8 + padding = 48 System.out.println("sizeOf(new Integer[3]) = " + sizeOf(new Integer[3])); System.out.println("fullSizeOf(new Integer[3]) = " + fullSizeOf(new Integer[3])); System.out.println("-------------------自定義數組對象---------------------------"); // 16 + (4+8) + padding = 32 System.out.println("sizeOf(new B()) = " + sizeOf(new B())); System.out.println("fullSizeOf(new B()) = " + fullSizeOf(new B())); // 24 + 0*8 + padding = 24 引用對象 64-bit JVM 占用 8 bytes, // 因為沒創建真實的 new B()所以 B類內部數據還未占用空間 System.out.println("sizeOf(new B[0]) = " + sizeOf(new B[0])); System.out.println("fullSizeOf(new B[0]) = " + fullSizeOf(new B[0])); // 24 + 1*8 + padding = 32 System.out.println("sizeOf(new B[1]) = " + sizeOf(new B[1])); System.out.println("fullSizeOf(new B[1]) = " + fullSizeOf(new B[1])); // 24 + 2*8 + padding = 40 System.out.println("sizeOf(new B[2]) = " + sizeOf(new B[2])); System.out.println("fullSizeOf(new B[2]) = " + fullSizeOf(new B[2])); // 24 + 3*8 + padding = 48 System.out.println("sizeOf(new B[3]) = " + sizeOf(new B[3])); System.out.println("fullSizeOf(new B[3]) = " + fullSizeOf(new B[3])); System.out.println("-------------------復合對象---------------------------"); // 16 + (4+8) + padding = 32 sizeOf 只計算單層次占用空間大小 System.out.println("sizeOf(new C()) = " + sizeOf(new C())); // (16 + (4+8) + padding1) + (24 + 2*8 + padding2) + 2*(16 + (4+8) + padding3) = 136 // 遞歸計算當前對象占用空間總大小,包括當前類和超類的實例字段大小以及實例字段引用對象大小 System.out.println("fullSizeOf(new C()) = " + fullSizeOf(new C())); System.out.println("-------------------繼承關系---------------------------"); // 涉及繼承關系的時候有一個最基本的規則:首先存放父類中的成員,接著才是子類中的成員, 父類也要按照 8 byte 規定 // 16 + 1 + padding = 24 System.out.println("sizeOf(new D()) = " + sizeOf(new D())); System.out.println("fullSizeOf(new D()) = " + fullSizeOf(new D())); // 16 + 父類(1 + padding1) + 1 + padding2 = 32 System.out.println("sizeOf(new E()) = " + sizeOf(new E())); System.out.println("fullSizeOf(new E()) = " + fullSizeOf(new E())); } public static class A { int a; Integer b; } public static class B { int a; Integer b; } public static class C{ int c; B[] b = new B[2]; // 初始化 C() { for (int i = 0; i < b.length; i++) { b[i] = new B(); } } } public static class D { byte d1; } public static class E extends D { byte e1; } }
------------------空對象---------------------------- sizeOf(new Object()) = 16 fullSizeOf(new Object()) = 16 ----------------非空對象含有原始類型、引用類型------------------------------ sizeOf(new A()) = 32 fullSizeOf(new A()) = 32 sizeOf(new Integer(1)) = 24 sizeOf(new String()) = 32 fullSizeOf(new String()) = 56 sizeOf(new String('a')) = 32 fullSizeOf(new String('a')) = 64 -------------------原始類型數組對象--------------------------- sizeOf(new byte[0]) = 24 fullSizeOf(new byte[0]) = 24 sizeOf(new byte[1]) = 32 fullSizeOf(new byte[1]) = 32 sizeOf(new char[1]) = 32 fullSizeOf(new char[1]) = 32 sizeOf(new byte[9]) = 40 fullSizeOf(new byte[9]) = 40 --------------------引用類型數組對象-------------------------- sizeOf(new Integer[0]) = 24 fullSizeOf(new Integer[0]) = 24 sizeOf(new Integer[1]) = 32 fullSizeOf(new Integer[1]) = 32 sizeOf(new Integer[1]) = 32 fullSizeOf(new Integer[1]) = 32 sizeOf(new Integer[3]) = 48 fullSizeOf(new Integer[3]) = 48 -------------------自定義數組對象--------------------------- sizeOf(new B()) = 32 fullSizeOf(new B()) = 32 sizeOf(new B[0]) = 24 fullSizeOf(new B[0]) = 24 sizeOf(new B[1]) = 32 fullSizeOf(new B[1]) = 32 sizeOf(new B[2]) = 40 fullSizeOf(new B[2]) = 40 sizeOf(new B[3]) = 48 fullSizeOf(new B[3]) = 48 -------------------復合對象--------------------------- sizeOf(new C()) = 48 fullSizeOf(new C()) = 152 -------------------繼承關系--------------------------- sizeOf(new D()) = 24 fullSizeOf(new D()) = 24 sizeOf(new E()) = 32 fullSizeOf(new E()) = 32