Java对象到底多大?

           很多时候我们想知道一个Java对象到底有多大, 但Java没有像C语言那样提供一个类似于sizeof的方法。作为Java老司机的你,是否考虑过这个问题?

     在《深入理解Java虚拟机》这边书中提到HotSpot虚拟机是8字节对齐的, 一个Java对象包括对象头(Header),实例数据(Instance Data)和对齐填充(Padding), 现在的HotSpot虚拟机一般运行在64位电脑上。

        不管是否压缩,即UseCompressOops。 Java对象占用字节数都是8的整数倍,8的整数倍,8的整数倍!!! 重要的事情说3遍。

          Object obj  = new Object();  请问在这句代码使用了多大内存?   不考虑压缩(XX:-UseCompressedOops),答案是24个字节, 其中引用obj在Java栈里使用8个字节, new Object在Java堆里使用16个字节。 


      Java Instrumentation类的getObjectToSize方法可以测量Java对象的大小, 要使用javagent注入的方式得到Instrumentation的引用。

/**
 * Returns an implementation-specific approximation of the amount of storage consumed by
 * the specified object. The result may include some or all of the object's overhead,
 * and thus is useful for comparison within an implementation but not between implementations.
 *
 * The estimate may change during a single invocation of the JVM.
 *
 * @param objectToSize     the object to size
 * @return an implementation-specific approximation of the amount of storage consumed by the specified object
 * @throws java.lang.NullPointerException if the supplied Object is <code>null</code>.
 */
long getObjectSize(Object objectToSize);

        我总结为表格, 方法理解大笑


Java语言有8种原生数据类型, 即8种类型关键字。原生类型(primitive type)的内存占用如下:

           类型                                          内存占用(字节)
boolean 1                                         
byte 1
short 2
char 2
int 4
float 4
long 8
double 8
            以上的8种数据类型压缩前后占用空间大小不变, 在32位/64位机器上占用空间一致, 即Java是平台无关的。


 下边是我总结的计算方法:

                                                  对象大小:(对象头 + 实例数据 + padding)%8等于0, padding是补齐成8的整数倍
                                                                         下面各个对象的大小都是按照上述顺序计算的。
对象             已压缩(字节)             -XX:+UseCompressedOops                     未压缩(字节)                 -XX:-UseCompressedOops 说明
new Object() 12+Padding=16 16 压缩前对象头占16个字节,压缩后占12个字节。
  static class A {  
        int a;     }                            new A()
12+4=16
12是对象头,4是int型大小
16+4+Padding=24
16是对象头大小,4是int型大小
对象头压缩前占16个字节,压缩后占12个字节;int型占4个字节。
 static class B {  
        int a;  
        int b;   }                          new B()  
12+4+4+Padding=24
12是对象头,第一个4是变量a,第二个4是变量b,  paddinb是余8补齐的4.
16+4+4=24 区别是已压缩要添加8字节对齐的Padding。
  static class B2 {  
        int b2a;  
       Integer b2b;  
    }                                new B2()
12+4+4=24
12是对象头,第一个4是变量b2a,第二个4是b2b引用。
16+4+8+Padding=32 在64位机器上引用压缩前占8个字节,压缩后占4个字节。
new Object[3] 16+3*4+Padding=32
16是对象头,4是单个引用大小。
24+8*3=48
24是对象头,8是单个引用大小
数组对象的对象头在压缩前占24个字节,压缩后占16个字节。
new Object[1] 16+1*4+padding=24
16是对象头,4是引用大小;
24+1*8=32
24是对象头,8是单个引用大小
 
单一对象头 12 16  
数组对象头 16 24  
引用 4 8  


              有兴趣的可以下载我用 IntelliJ写的demo工程:http://download.csdn.net/detail/brycegao321/9670233

1、新建Java工程;





2、设置输出为jar包, 得到MANIFEST.MF文件。


 

  选中 Build on make选项。


           修改MANIFEST.MF,  注意Boot-Class-Path后面有个空格!!!


MANIFEST.MF要添加下面三行
Premain-class: SizeUtils      (实现premain方法,得到Instrumentation的引用)
Can-Redefine-Classes: false
Boot-Class-Path:        (注意:Path:后面有空格,否则编译不过!!!)

编译后生成jar包。


测试代码:

public class SizeTest {
    /**
     * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 = 16
     * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + padding/4 = 24
     */
    static class A {
        int a;
    }

    /**
     * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
     * -XX:-UseCompressedOops: mark/8 + metedata/8 + 4 + 4 = 24
     */
    static class B {
        int a;
        int b;
    }

    /**
     * -XX:+UseCompressedOops: mark/4 + metedata/8 + 4 + 4 + padding/4 = 24
     * -XX:-UseCompressedOops: mark/8 + metedata/8 + 8 + 4 + padding/4 = 32
     */
    static class B2 {
        int b2a;
        Integer b2b;
    }

    /**
     * 不考虑对象头:
     * 4 + 4 + 4 * 3 + 3 * sizeOf(B)
     */
    static class C extends A {
        int ba;
        B[] as = new B[3];

        C() {
            for (int i = 0; i < as.length; i++) {
                as[i] = new B();
            }
        }
    }

    static class D extends B {
        int da;
        Integer[] di = new Integer[3];
    }

    /**
     * 会算上A的实例字段
     */
    static class E extends A {
        int ea;
        int eb;
    }

    public static void main(String[] args) throws IllegalAccessException {
        System.out.println("sizeOf(new Object())=" + SizeUtils.sizeOf(new Object()));
        System.out.println("sizeOf(new A())=" + SizeUtils.sizeOf(new A()));
        System.out.println("sizeOf(new B())=" + SizeUtils.sizeOf(new B()));
        System.out.println("sizeOf(new B2())=" + SizeUtils.sizeOf(new B2()));
        System.out.println("sizeOf(new B[3])=" + SizeUtils.sizeOf(new B[3]));
        System.out.println("sizeOf(new C())=" + SizeUtils.sizeOf(new C()));
        System.out.println("fullSizeOf(new C())=" + SizeUtils.fullSizeOf(new C()));
        System.out.println("sizeOf(new D())=" + SizeUtils.sizeOf(new D()));
        System.out.println("fullSizeOf(new D())=" + SizeUtils.fullSizeOf(new D()));
        System.out.println("sizeOf(new int[3])=" + SizeUtils.sizeOf(new int[3]));
        System.out.println("sizeOf(new Integer(1)=" + SizeUtils.sizeOf(new Integer(1)));
        System.out.println("sizeOf(new Integer[0])=" + SizeUtils.sizeOf(new Integer[0]));
        System.out.println("sizeOf(new Integer[1])=" + SizeUtils.sizeOf(new Integer[1]));
        System.out.println("sizeOf(new Integer[2])=" + SizeUtils.sizeOf(new Integer[2]));
        System.out.println("sizeOf(new Integer[3])=" + SizeUtils.sizeOf(new Integer[3]));
        System.out.println("sizeOf(new Integer[4])=" + SizeUtils.sizeOf(new Integer[4]));
        System.out.println("sizeOf(new A[3])=" + SizeUtils.sizeOf(new A[3]));
        System.out.println("sizeOf(new E())=" + SizeUtils.sizeOf(new E()));
        System.out.println("sizeOf(new HashMap)=" + SizeUtils.sizeOf(new HashMap<String,Object>()));
    }
}


输出:   左边是没压缩, 右边是压缩的, 单位是字节。 注意cmd命令啊!

java  -javaagent:CalcSize.jar -XX:+UseCompressedOops -jar CalcSize.jar 

java  -javaagent:CalcSize.jar -XX:-UseCompressedOops -jar CalcSize.jar



参考:

http://www.jroller.com/maxim/entry/again_about_determining_size_of

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

http://www.importnew.com/14948.html

展开阅读全文

没有更多推荐了,返回首页