一步步教你计算java对象的大小

内存布局

总计(byte):(m+c+f+p+l)%8=0

1、mark word->m

2、class对象指针->c

3、类字段->f

4、补齐位->p

5、如果是数组还有数组长度->l

引入依赖

 <dependency>
      <groupId>org.openjdk.jol</groupId>
      <artifactId>jol-core</artifactId>
      <version>0.9</version>
    </dependency>

测试案列

排序规则一

M=MarkWord

C=类型指针

I=数组长度

计算公式(M+C+I)%=0

类字段排列规则按照先基本类型,后引用类型,大的在前,小的在后,最后按声明顺序排列。从长到短排列,引用排最后: long/double --> int/float --> short/char --> byte/boolean --> Reference

关闭指针压缩

在这里插入图片描述

package com;
import org.openjdk.jol.info.ClassLayout;
public class TestClass {
    private String str;
    private long l;
    private int i;
    private byte b;
    private short s;

    public static void main(String[] args) {
        TestClass testClass = new TestClass();
        System.out.println(ClassLayout.parseInstance(testClass).toPrintable());
    }
}
com.TestClass object internals:
 OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                    (object header)                           28 30 dd 16 (00101000 00110000 11011101 00010110) (383594536)
     12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     8               long TestClass.l                               0
     24     4                int TestClass.i                               0
     28     2              short TestClass.s                               0
     30     1               byte TestClass.b                               0
     31     1                    (alignment/padding gap)                  
     32     8   java.lang.String TestClass.str                             null
Instance size: 40 bytes
Space losses: 1 bytes internal + 0 bytes external = 1 bytes total

结论1

结论:由于关闭了指针压缩,所以(M+C+I)%8=0,那么字段的排序规则符合先基本类型后引用类型,大的在前,小的在后。这句话是可以证明的,但是无法证明是按声明的字段排序的,因为上面的大小都不一样。

package com;
import org.apache.lucene.util.RamUsageEstimator;
import org.openjdk.jol.info.ClassLayout;

public class TestClass {
    private String str;
    private long l;
    private float f;
    private int i;
    private byte b;
    private boolean blen;
    private short s;
    public static void main(String[] args) {
        TestClass testClass = new TestClass();
        System.out.println(ClassLayout.parseInstance(testClass).toPrintable());
    }
}

调整位置前:

com.TestClass object internals:
 OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                    (object header)                           28 30 ba 17 (00101000 00110000 10111010 00010111) (398077992)
     12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     8               long TestClass.l                               0
     24     4              float TestClass.f                               0.0
     28     4                int TestClass.i                               0
     32     2              short TestClass.s                               0
     34     1               byte TestClass.b                               0
     35     1            boolean TestClass.blen                            false
     36     4                    (alignment/padding gap)                  
     40     8   java.lang.String TestClass.str                             null
Instance size: 48 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

调整位置后:

com.TestClass object internals:
 OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
      0     4                    (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4                    (object header)                           28 30 67 17 (00101000 00110000 01100111 00010111) (392638504)
     12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     8               long TestClass.l                               0
     24     4                int TestClass.i                               0
     28     4              float TestClass.f                               0.0
     32     2              short TestClass.s                               0
     34     1            boolean TestClass.blen                            false
     35     1               byte TestClass.b                               0
     36     4                    (alignment/padding gap)                  
     40     8   java.lang.String TestClass.str                             null
Instance size: 48 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

细细观察4个字节的和一个字节。

结论2

字段输出的顺序也是和声明字段的前后顺序是一样的,在字节大小相同的情况下。

排序规则二

计算公式(m+c+l)%8 !=0

优先从基本类型字段中找出一个 字段f,使得 (m+c+l+f) %8 =0,如64位jdk开启指针压缩的普通对象mark word+class refence = 12,如果类字段中有int或者float,会优先把这个字段排在前面 ,如果有多个的话,只会选择排在最前列的那个字段,其余字段按照规则一排列;如果没有int或者float,会根据大小的顺序选择 short char byte boolean,选择一个或多个字段大小和为4byte排列,如果只有一个上述字段,那就只排列一个,然后补空位到4byte。

开启指针压缩:

package com;
import org.apache.lucene.util.RamUsageEstimator;
import org.openjdk.jol.info.ClassLayout;

public class TestClass {
    private double a1;
    private short a2;
    private float a3;
    private  int a4;
    private  byte a5;
    private char a6;
    private long a7;
    private boolean a8;

    public static void main(String[] args) {
        TestClass testClass = new TestClass();
        System.out.println(ClassLayout.parseInstance(testClass).toPrintable());
    }
}

执行结果:

com.TestClass object internals:
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4           (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4           (object header)                           05 c1 00 20 (00000101 11000001 00000000 00100000) (536920325)
     12     4     float TestClass.a3                              0.0
     16     8    double TestClass.a1                              0.0
     24     8      long TestClass.a7                              0
     32     4       int TestClass.a4                              0
     36     2     short TestClass.a2                              0
     38     2      char TestClass.a6                               
     40     1      byte TestClass.a5                              0
     41     1   boolean TestClass.a8                              false
     42     6           (loss due to the next object alignment)
Instance size: 48 bytes
Space losses: 0 bytes internal + 6 bytes external = 6 bytes total

结论

由于开启了指针压缩这个类也没有数组所以(M+C+I)%8!=0,由于需要对齐,还缺少4个字节,由于float和int都是4个字节,但是排序规则是按照声明顺序的,所以是(M+C+I+F(float))=0,剩下的就按照排序规则进行排序了。

发布了60 篇原创文章 · 获赞 1 · 访问量 3323

猜你喜欢

转载自blog.csdn.net/qq_16438883/article/details/103806567