博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java对象到底多大?
阅读量:2349 次
发布时间:2019-05-10

本文共 5522 字,大约阅读时间需要 18 分钟。

           很多时候我们想知道一个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 null. */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: falseBoot-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
())); }}

输出:   左边是没压缩, 右边是压缩的, 单位是字节。 注意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

你可能感兴趣的文章
图像压缩算法
查看>>
一张图看懂小程序全生态
查看>>
electron开发
查看>>
NodeJS开发c++扩展模块
查看>>
Electron如何调用NodeJS扩展模块
查看>>
NodeJS通过ffi调用DLL
查看>>
Electron通过ffi调用DLL
查看>>
Node.js & Electron的扩展模块
查看>>
Mysql semi-sync VS group replication, 谁快?
查看>>
Android Looper Message MessageQueue Handler
查看>>
Win10下安装卸载Oracle11g的教程及各种坑
查看>>
Zookeeper
查看>>
更新mysql5.7修改字符集
查看>>
Windows系统护眼色设置
查看>>
JUC多线程&lambda之美&ThreadLocal
查看>>
碎片清理
查看>>
程序员不能错过的技术网站
查看>>
冒泡排序(分析+代码调优)
查看>>
Vue
查看>>
乐优商城总结
查看>>