欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入
先考虑下new Integer[0]占用的内存大小,长度为0,即是对象头的大小:
未开启压缩:24bytes
开启压缩后:16bytes
接着计算new Integer[1],new Integer[2],new Integer[3]和new Integer[4]就很容易了:
未开启压缩:
开启压缩:
拿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)当前对象占用的空间总大小
递归计算当前对象占用空间总大小,包括当前类和超类的实例字段大小以及实例字段引用对象大小。
递归计算复合对象占用的内存的时候需要注意的是:对齐填充是以每个对象为单位进行的,看下面这个图就很容易明白。
现在我们来手动计算下C对象占用的全部内存是多少,主要是三部分构成:C对象本身的大小+数组对象的大小+B对象的大小。
未开启压缩:
(16 + 4 + 8) + (24+ 8*3) +(16+8)*3 = 152bytes
开启压缩:
(12 + 4 + 4) + (16 + 4*3 +4(数组对象padding)) + (12+8+4(B对象padding))*3 = 96bytes
大家有兴趣的可以试试。
实际工作中真正需要手动计算对象大小的场景应该很少,但是个人觉得做为基础知识每个Java开发人员都应该了解,另外:对自己写的代码大概占用多少内存,内存中是怎么布局的应该有一个直觉性的认识。
[1][2]
年轻是我们唯一拥有权利去编织梦想的时光