对java文件头的解析

9次阅读

共计 1322 个字符,预计需要花费 4 分钟才能阅读完成。

java 对象保存在内存中时有 3 个部分

1. 对象头
2. 实例数据
3. 对齐填充字节

一. 对象头

​ java 的对象头有 3 部分组成:
​ 1.Mark Word
​ 2. 指向类的指针
​ 3. 数组长度 (如果是数组对象的话才有)

1.Mark Word

Mark Word 存储的内容 32bit 中如下所示:

其中无锁和偏向锁的锁标志位都是 01 只是用前一位来表示是无锁还是偏向锁

JDK1.6 后的版本在处理同步锁时存在锁升级的概念,JVM 对于同步锁的处理是从偏向锁开始的 处理方式从偏向锁升级到轻量锁 最终升级为重量级锁.

Ps : 锁只可单向升级 不可降级

JVM 一般是这样使用锁和 Mark Word 的:
JVM 一般是这样使用锁和 Mark Word 的:1,当没有被当成锁时,这就是一个普通的对象,Mark Word 记录对象的 HashCode,锁标志位是 01,是否偏向锁那一位是 0。2,当对象被当做同步锁并有一个线程 A 抢到了锁时,锁标志位还是 01,但是否偏向锁那一位改成 1,前 23bit 记录抢到锁的线程 id,表示进入偏向锁状态。3,当线程 A 再次试图来获得锁时,JVM 发现同步锁对象的标志位是 01,是否偏向锁是 1,也就是偏向状态,Mark Word 中记录的线程 id 就是线程 A 自己的 id,表示线程 A 已经获得了这个偏向锁,可以执行同步锁的代码。4,当线程 B 试图获得这个锁时,JVM 发现同步锁处于偏向状态,但是 Mark Word 中的线程 id 记录的不是 B,那么线程 B 会先用 CAS 操作试图获得锁,这里的获得锁操作是有可能成功的,因为线程 A 一般不会自动释放偏向锁。如果抢锁成功,就把 Mark Word 里的线程 id 改为线程 B 的 id,代表线程 B 获得了这个偏向锁,可以执行同步锁代码。如果抢锁失败,则继续执行步骤 5。5,偏向锁状态抢锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁。JVM 会在当前线程的线程栈中开辟一块单独的空间,里面保存指向对象锁 Mark Word 的指针,同时在对象锁 Mark Word 中保存指向这片空间的指针。上述两个保存操作都是 CAS 操作,如果保存成功,代表线程抢到了同步锁,就把 Mark Word 中的锁标志位改成 00,可以执行同步锁代码。如果保存失败,表示抢锁失败,竞争太激烈,继续执行步骤 6。6,轻量级锁抢锁失败,JVM 会使用自旋锁,自旋锁不是一个锁状态,只是代表不断的重试,尝试抢锁。从 JDK1.7 开始,自旋锁默认启用,自旋次数由 JVM 决定。如果抢锁成功则执行同步锁代码,如果失败则继续执行步骤 7。7,自旋锁重试之后如果抢锁依然失败,同步锁会升级至重量级锁,锁标志位改为 10。在这个状态下,未抢到锁的线程都会被阻塞。

2,指向类的指针

该指针在 32 位 JVM 中的长度是 32bit,在 64 位 JVM 中长度是 64bit。

Java 对象的类数据保存在方法区。

3,数组长度

只有数组对象保存了这部分数据。

该数据在 32 位和 64 位 JVM 中长度都是 32bit。

二,实例数据

对象的实例数据就是在 java 代码中能看到的属性和他们的值。

三,对齐填充字节

因为 JVM 要求 java 的对象占的内存大小应该是 8bit 的倍数,所以后面有几个字节用于把对象的大小补齐至 8bit 的倍数,没有特别的功能。

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

正文完
 0