java的markword_从Java对象布局markword看syncronized的本质

可以通过以下工具来查看Java对象的布局:JOL=Java Object Layout。

org.openjdk.jol

jol-core

0.10

先看下在JVM中,一个引用的长度占用多少字节:

import org.openjdk.jol.vm.VM;

public class JavaObjectLayout {

public static void main(String[] args) {

System.out.println("------------VM details---------------");

System.out.println(VM.current().details());

}

}

这个details()方法由JOL类库中的HotspotUnsafe类实现:

181f2f736ee5112463108562f84f030c.png

运行结果:

e89a1e92210249554ebfc5c0209f9223.png

运行结果中可以看到:

1.JVM是64位的HotSpot

2.默认开启oop(Ordinary Object Pointer,普通对象指针)压缩,可设置JVM参数-XX:-UseCompressedOops关闭指针压缩

3.默认开启Class pointer(类对象指针)的压缩,可设置JVM参数-XX:-UseCompressedClassPointer关闭指针压缩

4.对象按照8字节来对齐

5.对象属性(即上方的Field sizes by type)的长度:4字节(oopSize, 普通对象引用),其余的基本类型的字节数和java中一致

6.数组类型(即上方的Array element sizes)的长度:4字节(引用的长度),其余的基本类型的字节数和java中一致

由此可以得出,当前JVM使用4字节保存对象的引用。

(关于oop压缩和class pointer的压缩,可以参考这篇文章: https://blog.csdn.net/a469517790/article/details/104916916/ )

普通对象布局

mark word

8Bytes

用于标记锁信息、GC信息、IdentityHashCode等

Klass Pointer 类指针

4Bytes

用于标记该对象是哪个Class的实例

开启内存压缩(-XX:+UseCompressedClassPointer)后为4字节,默认是开启的,

不开启内存压缩为8个字节(下面有例子)

成员变量

视成员变量的类型和数量而定

如果没有成员变量,则这一块为空

Padding 对齐

视上述字节而定

一个对象占用的字节数必须是8的倍数,不足的用padding对齐

接下来看看普通对象的布局:编写代码:

import org.openjdk.jol.info.ClassLayout;

public class JavaObjectLayout {

public static void main(String[] args) {

System.out.println("------------Object---------------");

Object o = new Object();

String s = ClassLayout.parseInstance(o).toPrintable();

System.out.println(s);

}

}

f6f5d7034f8cfc5936833bf1855899d1.png

可以看到,前12个字节都是object header,什么是object header?引用OpenJDK的专业术语的原文:

object header

Common structure at the beginning of every GC-managed heap object. (Every oop points to an object header.) Includes fundamental information about the heap object's layout, type, GC state, synchronization state, and identity hash code. Consists of two words. In arrays it is immediately followed by a length field. Note that both Java objects and VM-internal objects have a common object header format.

对象头是由GC管理的,堆中的Java对象的开始部分,由两个word组成:mark word和klass pointer。

mark word

The first word of every object header. Usually a set of bitfields including synchronization state and identity hash code. May also be a pointer (with characteristic low bit encoding) to synchronization related information. During GC, may contain GC state bits.

klass pointer

The second word of every object header. Points to another object (a metaobject) which describes the layout and behavior of the original object. For Java objects, the "klass" contains a C++ style "vtable".

所以,这12字节中前8个字节(前两行)是markword,后4个字节(第三行)是对象指针。由于Object类没有成员变量,这块为空,因此最后4个字节(第四行)是对齐。

如果执行的时候使用JVM参数-XX:-UseCompressedClassPointers关闭类指针压缩,则class pointer将占用8字节:

9392fa026f3cc6403b1741412bc3fcd0.png

f8d1308d0efbf0157966a91781a877ef.png

数组对象布局

mark word

8Bytes

用于标记锁信息、GC信息、IdentityHashCode等

Klass Pointer

类指针

4Bytes

用于标记该对象是哪个Class的实例

开启内存压缩后为4字节,默认是开启的,

可通过(-XX:-UseCompressedClassPointer)关闭压缩,,关闭后为8字节

数组长度

4Bytes

标记数组有多少个元素

数组内容

根据数组类型m和长度n而定,长度为m*n

如果元素为基本类型,比如byte/boolean/short/char/int/long/double,则m为对应的基本类型长度;

如果元素为对象,m是4字节的引用

(前文已经提到:当前JVM使用4字节保存对象的引用)

如果数组长度为0,这一块为空

Padding 对齐

视上述字节而定

一个对象占用的字节数必须是8的倍数,不足的用padding对齐

同理可以查看数组对象的布局:

import org.openjdk.jol.info.ClassLayout;

public class JavaObjectLayout {

public static void main(String[] args) {

System.out.println("------------Object[2]---------------");

Object[] os = new Object[2];

System.out.println(ClassLayout.parseInstance(os).toPrintable());

}

}

f66c1f8a52017c713dc9b0c2c71ac24d.png

可以看到,从偏移量12开始,数组长度为4字节(上文object header的引用里提到,这两个words之后,紧接着就是数组长度),值为2,然后16字节开始,为2x4=8字节的数组内容(上文提到:每个对象的引用长度为4字节)。

syncronized关键字的本质

现在,我们去掉JVM参数,并用syncronized对该对象加锁,看看markword有什么变化:

import org.openjdk.jol.info.ClassLayout;

public class JavaObjectLayout {

public static void main(String[] args) {

System.out.println("------------Object---------------");

Object o = new Object();

synchronized (o) {

System.out.println(ClassLayout.parseInstance(o).toPrintable());

}

}

}

052e93712f79632488159f1cb11f86c4.png

可以看到,markword的前4个字节的内容发生了变化。因此,syncronized加锁的本质,是修改了该对象的markword。

来源:oschina

链接:https://my.oschina.net/itblog/blog/3213604

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值