JVM-理解java对象的堆内存结构

java对象在堆中的基本内存结构,分为三个部分:
1.对象头(header):包括Mark Word(标记字段)和Class Pointer(类型指针)
2.实例数据(instance data):对象真正存储的有效信息,即代码中定义的各种类型的字段内容
3.对齐填充(padding):由HotSpot虚拟机定义对象起始地址必须是8字节整数倍,当不是整数倍时,需要填充数据补齐,因为对补齐的数据访问只需要一次内存访问即可

一、对象头
Mark Word:
1.用于存储对象自身运行时数据,如HashCode、GC分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等
2.占用内存为一个机器码,32位系统一个机器码为4个字节,64位系统一个机器码为8字节
3.以32位系统为例:25Bit-对象的hashCode、4Bit-对象的分代年龄、1Bit-是否偏向锁、2Bit-锁标志位
4.通过MarkOop类型实现Mark Word,提供了大量方法用于查看当前对象头的状态,以及更新对象头的数据,为synchronized锁的实现提供了基础
5.不同锁状态下,存储数据不同,具体如下:

Class Pointer:
1.类型指针指向对象的类元数据,虚拟机通过这个指针确定该对象是哪个类的实例
2.占用内存为一个机器码,32位系统一个机器码为4个字节,64位系统一个机器码为8字节
3.所以一个对象头一般占用两个机器码,但是数组稍微特殊,使用三个机器码,其中一个机器码用来存放数组长度

二、实例数据
1.原生类型(primitive type)的内存占用如下:
Primitive Type
Memory Required(bytes)
boolean                      
1
byte                            
1
short                           
2
char                            
2
int                               
4
float                            
4
long                            
8
double    
8
2.引用类型在32位系统上每个占用4bytes, 在64位系统上每个占用8bytes

三、对齐填充
1.因为对齐填充达到的目的是使对象的内存地址达到8的整数倍,所以有以下公式:
(对象头+实例数据+padding)%8==0

实际演练:
问题:64位系统下new int[0]、new int[1]、Integer a的对象大小?
new int[0]:对象头(24字节)+实例数据(0字节)+对齐填充(前面计算结果为24,是8的整数倍,所以对齐填充字节为0)=24字节
new int[1]:对象头(24字节)+实例数据(基本类型4字节)+对齐填充(前面计算结果为28,需要加4才是8的整数倍,所以对齐填充字节为4)=32字节
Integer a:对象头(16字节)+实例数据(引用类型8字节)+对齐填充(前面计算结果为24,是8的整数倍,所以对齐填充字节为0)=24字节

上面的计算结果均是在未开启指针压缩的情况下,如果开启指针压缩,则计算结果会有差别,具体关于指针压缩的理解见后面的章节:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值