java 对象头
一、对象头
1.1 对象头介绍
java对象分为对象头,对象体,对齐字段,如下所示:
我们下面主要关注对象头的内容:
对象头 = Mark Word + Klass Word
如果是数组对象则:
对象头 = Mark Word + Klass Word + 数组长度
Klass Word:存储一个地址,长度取决于系统位数,32位和64位,该地址指向方法区中类的元数据信息。
常见的虚拟机分为32位和64位,则其对象头也会不同:
在32位系统中,Mark Word = 4 bytes = 32 bits,对象头 = 8 bytes = 64 bits;
在64位系统中,Mark Word = 8 bytes = 64 bits ,对象头 = 16 bytes = 128bits;
bytes 是字节,bits 是位。
- 32位虚拟机虚拟机普通对象头
|-----------------------------------------------------------|
| Object Header (64 bits) |
|---------------------------------|-------------------------|
| Mark Word (32 bits) | Klass Word (32 bits) |
|---------------------------------|-------------------------|
- 32位虚拟机虚拟机数组对象头
|---------------------------------------------------------------------------------|
| Object Header (96 bits) |
|--------------------------------|-----------------------|------------------------|
| Mark Word(32bits) | Klass Word(32bits) | array length(32bits) |
|--------------------------------|-----------------------|------------------------|
- 32位虚拟机Mark Word
|----------------------------------------------------------------------------------------------|
| Mark Word(32bits) | State |
|----------------------------------------------------------------------------------------------|
| hashcode:25 | age:4 | biased_lock:0 | lock:01 | Nomal |
|----------------------------------------------------------------------------------------------|
| thread:23 | epoch:2 | age:4 | biased_lock:1 | lock:01 | Biased |
|----------------------------------------------------------------------------------------------|
| ptr_to_lock_record:30 | lock:00 | Lightweight Locked |
|----------------------------------------------------------------------------------------------|
| ptr_to_heavyweight_monitor:30 | lock:10 | Heavyweight Locked |
|----------------------------------------------------------------------------------------------|
| | lock:11 | Marked for GC |
|----------------------------------------------------------------------------------------------|
- 64位虚拟机虚拟机普通对象头
|--------------------------------------------------------------------------------------------|
| Object Header(128bits) |
|--------------------------------------------------------------------------------------------|
| Mark Word(64bits) | Klass Word(64bits) |
|--------------------------------------------------------------------------------------------|
- 64位虚拟机虚拟机数组对象头
|---------------------------------------------------------------------------------------------------------|
| Object Header (192 bits) |
|--------------------------------|-----------------------|------------------------|-----------------------|
| Mark Word(64bits) | Klass Word(64bits) | array length(32bits) | alignment(32bits) |
|--------------------------------|-----------------------|------------------------|-----------------------|
在数组对象当中,有一个对齐长度(alignment/padding gap)是8字节,但是其中是包含数组长度4个字节,所以对齐字节长度也是4,具体可以看我下一小节的演示。
- 64位虚拟机Mark Word
|----------------------------------------------------------------------------------------------|
| Mark Word(64bits) | State |
|----------------------------------------------------------------------------------------------|
| unused:25|identity_hashcode:31|unused:1|age:4|biase_lock:0| lock:01 | Nomal |
|----------------------------------------------------------------------------------------------|
| thread:54| epoch:2 |unused:1|age:4|biase_lock:1| lock:01 | Biased |
|----------------------------------------------------------------------------------------------|
| ptr_to_lock_record:62 | lock:00 | Lightweight Locked |
|----------------------------------------------------------------------------------------------|
| ptr_to_heavyweight_monitor:62 | lock:10 | Heavyweight Locked |
|----------------------------------------------------------------------------------------------|
| | lock:11 | Marked for GC |
|----------------------------------------------------------------------------------------------|
1.2 查看对象头
引入下列依赖:
<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
本文并没有使用网上大家都在使用的0.10版本,因为对比后我发现,新版本0.16更能清晰的体现对象头的内容。同学们可以自行对比下。
首先声明两个JVM的参数:
- -XX:-UseCompressedOops 关闭压缩
- -XX:+UseCompressedOops 开启压缩
我的是默认开启的,所以需要使用-XX:-UseCompressedOops将其关闭。
下面会简单模拟是普通对象和数组对象,我的电脑都是64位的,即参照64位虚拟机的结果。
给定一个空的Student对象:
public class Student {
}
测试类如下:
public class ObjectHeader {
public static void main(String[] args) {
//对象
Student student = new Student();
//数组
String[] strings = new String[]{};
// 打印jvm的具体参数
System.out.println(VM.current().details());
// 打印普通对象头信息
System.out.println(ClassLayout.parseInstance(student).toPrintable());
// 打印数组对象头信息
System.out.println(ClassLayout.parseInstance(strings).toPrintable());
}
}
结果如下:
Connected to the target VM, address: '127.0.0.1:63960', transport: 'socket'
# Running 64-bit HotSpot VM.
# Objects are 8 bytes aligned.
# Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
com.cloud.bssp.thread.objectheader.Student object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 8 (object header: class) 0x000000001c2b1cd0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
[Ljava.lang.String; object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000000000000001 (non-biasable; age: 0)
8 8 (object header: class) 0x000000001bfa4268
16 4 (array length) 0
16 8 (alignment/padding gap)
24 0 java.lang.String String;.<elements> N/A
Instance size: 24 bytes
Space losses: 8 bytes internal + 0 bytes external = 8 bytes total
下面我们逐行进行讲解:
- JVM参数
// 64位虚拟机
Running 64-bit HotSpot VM.
// 按照8个字节对齐,即忽略第一个8字节
Objects are 8 bytes aligned.
// 忽略8字节后,余下的其实都是基本类型所占的字节:boolean,byte,char,short,int,float,long,double的大小
Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
// 数组中元素所占字节,同上面
>Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
- 普通对象 com.cloud.bssp.thread.objectheader.Student
// 很明显,下面是mark word的大小,8个字节,64bits
object header: mark
// 如下是klass word的大小,8个字节,64bits
object header: class
// 实例大小是16字节。
Instance size: 16 bytes
//空间损失,是否有对其字节,内部对齐和外部对齐
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
- 数组对象 [Ljava.lang.String; object
// 很明显,下面是mark word的大小,8个字节,64bits
object header: mark
// 如下是klass word的大小,8个字节,64bits
object header: class
// 数组长度
array length
// 内部的对齐字节大小
alignment/padding gap
// 空数组
java.lang.String String;.<elements> N/A
// 实例大小是24
Instance size: 24 bytes
//空间损失,8个是内部对齐字节,其中包含字节的长度4,也就是补齐了4个
Space losses: 8 bytes internal + 0 bytes external = 8 bytes total
二、Mark Word简介
这一节简单介绍小Mark Word当中的参数都是什么意思,以64位虚拟机介绍。
|----------------------------------------------------------------------------------------------|
| Mark Word(64bits) | State |
|----------------------------------------------------------------------------------------------|
| unused:25|identity_hashcode:31|unused:1|age:4|biase_lock:0| lock:01 | Nomal |
|----------------------------------------------------------------------------------------------|
| thread:54| epoch:2 |unused:1|age:4|biase_lock:1| lock:01 | Biased |
|----------------------------------------------------------------------------------------------|
| ptr_to_lock_record:62 | lock:00 | Lightweight Locked |
|----------------------------------------------------------------------------------------------|
| ptr_to_heavyweight_monitor:62 | lock:10 | Heavyweight Locked |
|----------------------------------------------------------------------------------------------|
| | lock:11 | Marked for GC |
|----------------------------------------------------------------------------------------------|
先看state这一列,由上至下分别代表synchronized锁的状态:无锁,偏向锁,轻量级锁,重量级锁,GC。每个锁的含义将在下一篇文章重点讲解。
下面以行为单位,由上至下查看:
-
Nomal (无锁)
unused:未使用25位
identity_hashcode:31位的对象标识hashCode
unused:未使用1位
age:4位的Java对象GC回收年龄。
biase_lock:1位偏向锁标记,0未启用
locked:2位锁状态标志位,配合biased_lock表示java对象各阶段不同锁状态。 -
Biased(偏向锁)
thread:54位的持有偏向锁的线程id
epoch:偏向锁的时间戳
unused:未使用1位
age:4位的Java对象GC回收年龄。
biase_lock:1位偏向锁标记,1启用
locked:2位锁状态标志位,配合biased_lock表示java对象各阶段不同锁状态。 -
Lightweight Locked(轻量级锁)
ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针。
locked:2位锁状态标志位,00表示轻量级锁。 -
Heavyweight Locked(重量级锁)
ptr_to_heavyweight_monitor:重量级锁状态下,指向Monitor(监视器或管程,下一篇文章讲解)的指针。
locked:2位锁状态标志位,10表示轻量级锁。 -
Marked for GC(GC标记)
locked:2位锁状态标志位,11表示被标记为垃圾回收。
关于对象头的内容,目前就介绍这么多,下一篇文章会讲解synchronized的相关内容和原理。有用的话给个关注,点赞吧!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
2022-02-16 mysql学习 实践(1) 普通索引和唯一索引的选择
2022-02-16 mysql学习 索引(2)
2022-02-16 单调队列
2022-02-16 mysql学习 索引(1)