了解java对象结构+计算+验证
最近仔细研究了一下java中的锁,发现首先基础知识不可缺少的就是java的对象结构,因为锁的相关信息是在对象的头中的,所以我们先来了解一下对象的结构。
对象分为数组对象和普通对象,它们之间有细微的差别,如下图:
以下是对上面组成部分的解释:
一、对象头:
1、MarkWord
第一部分markword,用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,最重要的一部分。
2、Klass
对象头的另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例.
3、数组长度(只有数组对象有)
如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度.
注意,在不同位数的计算机上,他们的大小不是固定的
简单解释下,就是MarkWord在32bit的机器上为4位,在64bit的机器上位8位。Klass在32bit的机器上为4位,在64bit的机器上,如果开启了对象指针压缩为4位,否则位8位,数组长度都为8位。
指针压缩:若 JVM 开启 Klass 指针压缩选项( -XX:+UseCompressedClassPointers,JVM 默认开启此选项 ),则用 4 字节表示;若不开启指针压缩( -XX:-UseCompressedOops )则用 8 字节表示;32 位系统则使用 4 字节表示。
二、对象实例数据
这是对象定义的基本数据类型,大家都知道,java对象在new的时候,大小就已经确定了.
基本数据类型 | 字节大小 |
byte | 1B |
boolean | 1B |
short | 2B |
char | 2B |
int | 4B |
float | 4B |
long | 8B |
double | 8B |
稍后我们会计算一个对象的大小加以验证。
三、对齐填充
第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
四、使用例子来计算对象的大小
package com.example.demo.jvm.entiry; import org.springframework.stereotype.Component; /** * @Author: caesar * @Date:2021年01月01日 17:01:46 * @Description: 测试类 */ @Component public class Item { private int id; }
我是64bit的机器,未开启指针压缩,所以大小计算为:
对象大小:对象头+对象示例数据+对齐填充 = MarkWord+Klass+int类型+对其填充 = 8B + 8B + 4B + 0B= 20B
你怎末知道?
没关系,来验证一下:
如果安装了java环境,先启动SpringBoot项目,然后cmd执行jvisualvm, 点击这里
查看,是20没问题
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步