java对象占内存大小

本文详细介绍了Java中对象的内存布局,包括对象头、实例数据和对齐填充等组成部分,并探讨了不同环境下对象大小的变化,以及开启指针压缩对内存占用的影响。

好多东西记不清楚了,网络上收集的合到一起吧,没事儿看看

222447_QGbB_35343.png

 

1B(byte 字节)=8bit

1KB(Kilobyte 千字节)=1024B,

1MB(Megabyte 兆字节 简称“兆”)=1024KB,

1GB(Gigabyte 吉字节 又称“千兆”)=1024MB,

1TB(Terabyte 万亿字节 太字节)=1024GB,

1PB(Petabyte 千万亿字节 拍字节)=1024TB,

1EB(Exabyte 百亿亿字节 艾字节)=1024PB,

1ZB(Zettabyte 十万亿亿字节 泽字节)= 1024EB,

1YB(Yottabyte 一亿亿亿字节 尧字节)= 1024ZB,

 

Java对象的内存布局:对象头(Header),实例数据(Instance Data)和对齐填充(Padding)。另外:不同的环境结果可能有差异。 

对象头

对象头在32位系统上占用8bytes,64位系统上占用16bytes。

 

222945_TTmi_35343.png

 

222930_XEqD_35343.png

实例数据

原生类型(primitive type)的内存占用如下:

Primitive TypeMemory Required(bytes)
boolean                      1
byte                            1
short                           2
char                            2
int                               4
float                            4
long                            8
double    8

reference类型在32位系统上每个占用4bytes, 在64位系统上每个占用8bytes。

对齐填充

HotSpot的对齐方式为8字节对齐:

(对象头 + 实例数据 + padding) % 8等于0且0 <= padding < 8

指针压缩

对象占用的内存大小收到VM参数UseCompressedOops的影响。

1)对对象头的影响

开启(-XX:+UseCompressedOops)对象头大小为12bytes(64位机器)。

static class A {
        int a;
    }

 

A对象占用内存情况:

关闭指针压缩: 16+4=20不是8的倍数,所以+padding/4=24

223205_qQtw_35343.png

开启指针压缩: 12+4=16已经是8的倍数了,不需要再padding。

223222_0D25_35343.png

1) 对reference类型的影响

64位机器上reference类型占用8个字节,开启指针压缩后占用4个字节。

static class B2 {
        int b2a;
        Integer b2b;
}

B2对象占用内存情况:

关闭指针压缩: 16+4+8=28不是8的倍数,所以+padding/4=32

223312_fZjd_35343.png

开启指针压缩: 12+4+4=20不是8的倍数,所以+padding/4=24

223332_BuC0_35343.png

数组对象

64位机器上,数组对象的对象头占用24个字节,启用压缩之后占用16个字节。之所以比普通对象占用内存多是因为需要额外的空间存储数组的长度。

先考虑下new Integer[0]占用的内存大小,长度为0,即是对象头的大小:

未开启压缩:24bytes

223356_9Df4_35343.png

开启压缩后:16bytes

223414_3enY_35343.png

接着计算new Integer[1],new Integer[2],new Integer[3]和new Integer[4]就很容易了:

未开启压缩:

223433_Awzf_35343.png

开启压缩:

223448_BxEW_35343.png

拿new Integer[3]来具体解释下:

未开启压缩:24(对象头)+8*3=48,不需要padding;

开启压缩:16(对象头)+3*4=28,+padding/4=32,其他依次类推。

自定义类的数组也是一样的,比如:

static class B3 {
        int a;
        Integer b;
    }

new B3[3]占用的内存大小:

未开启压缩:48

开启压缩后:32

复合对象

计算复合对象占用内存的大小其实就是运用上面几条规则,只是麻烦点。

1)对象本身的大小

直接计算当前对象占用空间大小,包括当前类及超类的基本类型实例字段大小、引用类型实例字段引用大小、实例基本类型数组总占用空间、实例引用类型数组引用本身占用空间大小; 但是不包括超类继承下来的和当前类声明的实例引用字段的对象本身的大小、实例引用数组引用的对象本身的大小。

static class B {
        int a;
        int b;
    }
static class C {
        int ba;
        B[] as = new B[3];

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

未开启压缩:16(对象头)+4(ba)+8(as引用的大小)+padding/4=32

开启压缩:12+4+4+padding/4=24

 

2)当前对象占用的空间总大小

递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。

递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。

223724_TfQq_35343.png

现在我们来手动计算下C对象占用的全部内存是多少,主要是三部分构成:C对象本身的大小+数组对象的大小+B对象的大小。

未开启压缩:

(16 + 4 + 8+4(padding)) + (24+ 8*3) +(16+8)*3 = 152bytes

开启压缩:

(12 + 4 + 4 +4(padding)) + (16 + 4*3 +4(数组对象padding)) + (12+8+4(B对象padding))*3= 128bytes

 

 

转载于:https://my.oschina.net/wtsoftware/blog/1590717

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值