网上结论多以32位系统为主。本文基于64位,力求简介,不会写太多废话,但能保证写出来的都是可供验证的客观事实。

验证工具:jol-cli

代码环境:64位 windows系统

Java普通对象的组成【非数组】

三部分:对象头实例数据对齐填充

对象头

开启指针压缩8 byte + 4 byte =12 byte ==> 96 bit **默认**✔

不开启指针压缩8 byte + 8 byte =16 byte ==> 128 bit

Mark Word

64位 Win环境下,Mark Word占 8 byte ==> 64bit

image-20201102131302955

此处仅讨论无锁【Normal】状态下:25 + 31 + 1 + 4 + 1 + 2 = 64 bit。

Klass 指针【指向其类的元数据的指针】

JVM通过这个指针确定对象是哪个类的实例。

  • 开启指针压缩:4 byte
  • 不开启指针压缩:8 byte

实例数据

对象中实实在在的数据:int 4,short 2,long 8,byte 1,char 2 ,float 4,double 8,单位byte,转bit *8。

对齐填充

JVM要求Java对象的大小必须是8 byte的整数倍,所以为了填充到整数倍,设置了对齐填充区。

证实

1
2
3
4
public class TestObj {
int i = 1;
short a = 2;
}

利用jol-cli在main中打印出对象信息如下:

image-20201102152658405

前三行为对象头,默认开启了指针压缩,所以12 byte,(一行4 byte,3行)。跟着一个int占4 byte,1行;一个short占2 byte,半行。 由于Java对象必须为8 byte的整数倍,所以灰色为对齐填充,占6 byte。

window环境下,对象头的高位是最右边,所以看对象头中Mark Word区域时候要从后往前看

此时为无锁状态,对象头中,前25位无用,均为0。

跟着31位为HashCode值,可以看到和打印出来的HashCode和我们所料一样。

最后8位代表gc年龄、锁状态等信息。

总结

64位 开启指针压缩,对象分布如下:

总结