了解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没问题

 

posted @ 2021-01-03 15:45  码在江湖  阅读(104)  评论(0编辑  收藏  举报