您的当前位置:首页正文

一个对象占用多少字节?

来源:九壹网

  • http://yueyemaitian.iteye.com/blog/2033046

        老早之前写过一篇博客,是关于一个Integer对象到底占用多少字节的,现在看来,那篇文章竟然计算错了。这次再去计算,是因为之前写的一篇的文章里,看到了hotspot jvm里,对象占用空间是的,再加上之前关于字节那文章里带着一点-XX:+UseCompressedOops压缩指针参数的疑问,重新探究了下一个对象到底占用多少字节,以及如何计算它占用空间的方法。主要是参考了,不过试验了一把,instrumentation这种方法还是靠谱的。

Java代码  

       跑代码前,需要按照那篇很老的文章先打包,这样才能注入Instrumentation实例,打包时候需要在MANIFEST.MF中写入三项值(注意包路径名改成自己的包名):

Java代码  
  1. Premain-class: xxx.yyy.zzz.SizeOfObject  
  2. Can-Redefine-Classes: false  
  3. Boot-Class-Path:   

        来看看测试类:

Java代码  
  1. import java.io.File;  
  2. import static com.tmall.buy.structure.SizeOfObject.*;  
  3. /** 
  4.  * @author tianmai.fh 
  5.  * @date 2014-03-18 20:17 
  6.  */  
  7. public class SizeOfObjectTest {  
  8.     /** 
  9.      * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 = 16 
  10.      * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + padding/4 = 24 
  11.      */  
  12.     static class A {  
  13.         int a;  
  14.     }  
  15.   
  16.     /** 
  17.      * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24 
  18.      * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24 
  19.      */  
  20.     static class B {  
  21.         int a;  
  22.         int b;  
  23.     }  
  24.   
  25.     /** 
  26.      * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24 
  27.      * -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + 4 + padding/4 = 32 
  28.      */  
  29.     static class B2 {  
  30.         int b2a;  
  31.         Integer b2b;  
  32.     }  
  33.   
  34.     /** 
  35.      * 不考虑对象头: 
  36.      * 4 + 4 + 4 * 3 + 3 * sizeOf(B) 
  37.      */  
  38.     static class C extends A {  
  39.         int ba;  
  40.         B[] as = new B[3];  
  41.   
  42.         C() {  
  43.             for (int i = 0; i < as.length; i++) {  
  44.                 as[i] = new B();  
  45.             }  
  46.         }  
  47.     }  
  48.   
  49.     static class D extends B {  
  50.         int da;  
  51.         Integer[] di = new Integer[3];  
  52.     }  
  53.   
  54.     /** 
  55.      * 会算上A的实例字段 
  56.      */  
  57.     static class E extends A {  
  58.         int ea;  
  59.         int eb;  
  60.     }  
  61.   
  62.     public static void main(String[] args) throws IllegalAccessException {  
  63.         System.out.println(new File("./target/classes").getAbsolutePath());  
  64.         System.out.println("sizeOf(new Object())=" + sizeOf(new Object()));  
  65.         System.out.println("sizeOf(new A())=" + sizeOf(new A()));  
  66.         System.out.println("sizeOf(new B())=" + sizeOf(new B()));  
  67.         System.out.println("sizeOf(new B2())=" + sizeOf(new B2()));  
  68.         System.out.println("sizeOf(new B[3])=" + sizeOf(new B[3]));  
  69.         System.out.println("sizeOf(new C())=" + sizeOf(new C()));  
  70.         System.out.println("fullSizeOf(new C())=" + fullSizeOf(new C()));  
  71.         System.out.println("sizeOf(new D())=" + sizeOf(new D()));  
  72.         System.out.println("fullSizeOf(new D())=" + fullSizeOf(new D()));  
  73.         System.out.println("sizeOf(new int[3])=" + sizeOf(new int[3]));  
  74.         System.out.println("sizeOf(new Integer(1)=" + sizeOf(new Integer(1)));  
  75.         System.out.println("sizeOf(new Integer[0])=" + sizeOf(new Integer[0]));  
  76.         System.out.println("sizeOf(new Integer[1])=" + sizeOf(new Integer[1]));  
  77.         System.out.println("sizeOf(new Integer[2])=" + sizeOf(new Integer[2]));  
  78.         System.out.println("sizeOf(new Integer[3])=" + sizeOf(new Integer[3]));  
  79.         System.out.println("sizeOf(new Integer[4])=" + sizeOf(new Integer[4]));  
  80.         System.out.println("sizeOf(new A[3])=" + sizeOf(new A[3]));  
  81.         System.out.println("sizeOf(new E())=" + sizeOf(new E()));  
  82.     }  
  83. }  

         如果你是用maven打包的话,可以考虑。打完jar包后,可以直接运行SizeOfObject了,但是要加上vm启动参数(test.jar是刚才打的jar包):

Java代码  
  1. -javaagent:target/test.jar   

         在我64bit mac上,跑64位hotspot vm的结果如下,其中压缩对象指针参数是开启的,即-XX:+UseCompressedOops

Java代码  
  1. sizeOf(new Object())=16  
  2. sizeOf(new A())=16  
  3. sizeOf(new B())=24  
  4. sizeOf(new B2())=24  
  5. sizeOf(new B[3])=32  
  6. sizeOf(new C())=24  
  7. fullSizeOf(new C())=128  
  8. sizeOf(new D())=32  
  9. fullSizeOf(new D())=64  
  10. sizeOf(new int[3])=32  
  11. sizeOf(new Integer(1)=16  
  12. sizeOf(new Integer[0])=16  
  13. sizeOf(new Integer[1])=24  
  14. sizeOf(new Integer[2])=24  
  15. sizeOf(new Integer[3])=32  
  16. sizeOf(new Integer[4])=32  
  17. sizeOf(new A[3])=32  
  18. sizeOf(new E())=24  

         如果关闭指针压缩,即在vm启动参数中加上-XX:-UseCompressedOops结果会不一样:

Java代码  
  1. sizeOf(new Object())=16  
  2. sizeOf(new A())=24  
  3. sizeOf(new B())=24  
  4. sizeOf(new B2())=32  
  5. sizeOf(new B[3])=48  
  6. sizeOf(new C())=40  
  7. fullSizeOf(new C())=160  
  8. sizeOf(new D())=40  
  9. fullSizeOf(new D())=88  
  10. sizeOf(new int[3])=40  
  11. sizeOf(new Integer(1)=24  
  12. sizeOf(new Integer[0])=24  
  13. sizeOf(new Integer[1])=32  
  14. sizeOf(new Integer[2])=40  
  15. sizeOf(new Integer[3])=48  
  16. sizeOf(new Integer[4])=56  
  17. sizeOf(new A[3])=48  
  18. sizeOf(new E())=32  

         UseCompressOops开启和关闭,对对象头大小是有影响的,开启压缩,对象头是4+8=12byte;关闭压缩,对象头是8+8=16bytes。这个如何观察验证呢?

        基于上述事实,通过new A()和new B()占用字节推断,基本类型int在开启、关闭压缩情况下都是占用4个bytes的,这个没有影响。而通过B和B2在开启、关闭指针压缩情况下的对比看,Integer类型分别占了4 bytes和8 bytes,实际上引用类型都是这样。如何验证?

         new Integer[0]在压缩前后分别占用16、24个字节,这是又是为什么呢?

        欲知后事,!enjoy it !

因篇幅问题不能全部显示,请点此查看更多更全内容

Top