jvm在32位和64位环境下对象占用空间对比

       在C/C++语言中,sizeof它可以获取一个对象或者类型所占的内存字节数。在C/C++中需要sizeof是因为移植,不同的数据类型在不同的机器上大小可能不同,程序员必须知道对应的数据类型大小。

       为什么Java中没有sizeof()?Java是一种纯面向对象的编程语言,它将内存管理的细节都交给Java Virtual MachineJVM)进行管理。我们都说java是跨平台的,这里的平台确切说是jvm,java可以在任意版本的jvm上运行。但是jvm不是跨操作系统平台的,jvm主要用C语言编写的。操作系统种类是有限的,oracle公司在各种操系下都发布jvm。这样就间接的实现了java跨操作系统平台。

      Windows Jvm32位和64位两版本。8种基本数据类型占用的空间都是一样的,new一个对象所占用的空间却很大差异。

对象

32位(byte

64位(byte

new Object()

8

16

new Integer(1)

16

16

new Short((short) 1)

16

16

new Boolean(true)

16

16

new Byte((byte) 0)

16

16

new Character((char) 1)

16

16

new Float(1)

16

16

new Double(1)

16

24

new Long(1)

16

24

new String()

16

24

new Object[0]

16

16

new Object[1]

16

24

new Object[2]

24

24

new Object[3]

24

32

new Object[4]

32

32

new Object[5]

32

40

表格中的数据获取方法:

public class TestSize {

    public static void main(String args[]) throws Exception {
        sizeOf();
    }
    private static Object types() {
        return new Object();
//        return new Integer(1);
//        return new Short((short) 1);
//        return new Long(1);
//        return new Byte((byte) 0);
//        return new Character((char) 1);
//        return new Float(1);
//        return new Double(1);
//        return new Boolean(true);
//        return new String();

//        return new Object[0];
//        return new Object[1];
//        return new Object[2];
//        return new Object[3];
//        return new Object[4];
//        return new Object[5];
    }
    private static final Runtime rTime = Runtime.getRuntime();

    private static void sizeOf() {

        final int count = 100000;
        Object[] objs = new Object[count];
        runGC();
        long heapSizeBefore = usedMemory();   // before memory size
        for (int i = 0; i < count; i++) {
            objs[i] = types();
        }
        runGC();
        long heapSizeAfter = usedMemory();      // after memory size
        System.out.println("heapSizeBefore = " + heapSizeBefore);
        System.out.println("heapSizeAfter  = " + heapSizeAfter);
        Long size = Math.round((heapSizeAfter - heapSizeBefore) / (double) count);
        System.out.println(objs[0].getClass().getSimpleName() + "_size=" + size);

    }
    private static void runGC() {
        long usedMemOld = 0;
        long usedMemNew = usedMemory();
        while (usedMemOld != usedMemNew) {//循环多次
            rTime.runFinalization();//强制调用已经失去引用的对象的finalize方法
            rTime.gc();//进行垃圾收集
            Thread.yield();//使当前线程从执行状态(运行状态)变为可执行态(就绪状态),给jvm去执行gc
            usedMemOld = usedMemNew;
            usedMemNew = usedMemory();
        }
    }
    private static long usedMemory() {
        return rTime.totalMemory() - rTime.freeMemory();
    }
}

1、观察上表,可以发现对象占用空间都是是8的倍数。

1.1、对象数组是存放对象地址的,在32位环境下,new Object[0]16btyenew Object[1]16btyenew Object[2]24btyenew Object[3]24btyenew Object[4]32btyenew Object[5]32byte。我们可以得出地址位占4btye。new Object[2]和new Object[3]为什么都占24byte,其实Object[2]只需要20btye就可以了,但是20不是8的倍数,所以又加了4byte。在64位环境下也是如此。

1.2、32操作系统最大支持4G内存,2^32/(1024*1024*1024)=4G。64操作系统理论是2^64/(1024*1024*1024)=17179869184G,实际中不可能用到这么大的内存,目前64位windows系统最大只支持192G,而当前最好主板只能加到64G,主流还是16G。有没有发现一个问题,32位和64位jvm中地址为都是占用4byte(32bit),32bit的寻址范围是0~4G,32位jvm是没有问题的,但是64位jvm的地址位按常理来推算应该是64/8=8bye,为什么是4byte?这就涉及到jvm的指针压缩技术。当jvm是64位且内存小于32G会默认开启指针压缩技术。什么是指针压缩技术?简单的理解就是:jvm分配内存空间都是8byte的倍数,那么8byte就是jvm分配内存的最单位,因此8byte只需要一个地址,2^32*8byte=32G,指针压缩技最大只能支持32G。

1.3、禁止使用指针压缩技术。 -XX:+UseCompressOops

电脑配置:jvm64位,8G内存。
对象 空间 byte
new Object[0] 24
new Object[1] 32
new Object[2] 40
new Object[3] 48
new Object[4] 56
new Object[5] 64





猜你喜欢

转载自blog.csdn.net/hong10086/article/details/79899961