java分块布局_JAVA并发(1)—java对象布局

使用synchronized关键字,是锁对象还是锁代码块呢?

在hotSpot虚拟机中,对象在内存中的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

8dd5a54237dd

如何查看JDK版本号.png

而实际上,对象在堆上分配的内存为8的整数倍,若对象头和实例数据大小不是8的整数倍时,才需要对齐填充。

如何查看对象布局

org.jolokia

jolokia-core

public static void main(String[] args) {

Account account=new Account();

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

}

2.1 对齐填充是否一定存在?

public class Account {

//只有一个boolean的属性,即占1byte。

boolean flag=false;

}

打印出的对象布局:

com.tellme.lock.Account object internals:

OFFSET SIZE TYPE DESCRIPTION VALUE

0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)

4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)

8 4 (object header) 43 21 f3 27 (01000011 00100001 11110011 00100111) (670245187)

12 1 boolean Account.flag false

13 3 (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

结论:

对象头部分占用12byte;

实例数据部分占用的是1byte;

对齐填充部分占用了3byte,将其补充为8的整数倍。

public class Account {

//若是int类型,那么实例数据占用的是4字节

int flag=0;

}

重写打印对象布局:

com.tellme.lock.Account object internals:

OFFSET SIZE TYPE DESCRIPTION VALUE

0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)

4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)

8 4 (object header) 43 e1 e2 27 (01000011 11100001 11100010 00100111) (669180227)

12 4 int Account.flag 0

Instance size: 16 bytes

Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

可以看到,此时对象的布局为对象头和实例数据。并不存在填充数据。

2.2 Java对象头

有上面数据可以看出,对象头大小为12byte,也就是96bit。

8dd5a54237dd

JVM虚拟机文档.png

可以看到,对象头由两部分组成:

1. mark word:用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、同步状态等。

2. klass pointer:对象指向它的类元数据的指针,虚拟机可以通过这个指针来确定这个对象是哪个类的实例(数组、对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通JAVA对象的元数据信息确定JAVA对象的大小,但是从数组的元数据中无法确定数组的大小)。

8dd5a54237dd

图1-32位HotSpot虚拟机对象头Mark Word组成.png

在mark word中分代年龄占了4bit,即分代年龄值为0-15

在JVM调优中:

-XX:MaxTenuringThreshold默认15。即理论上每发生一次GC,对象的分代年龄+1;

GC标记的锁标志位为11,是GC的markSweep(标记清除算法)使用的。

在并发编程中:

synchronize关键字对对象加锁,实际上是锁的对象,而并非对代码块进行加锁。而锁对象正是通过mark word的同步标识来实现的。具体到上图中就是通过是否偏向锁+锁标识字段来控制对象的五种标识的。

8dd5a54237dd

image.png

注:age:保存对象的分代年龄||biased_lock:偏向锁标识位||lock:锁状态标识位||epoch:保存偏向时间戳。

不管是32/64位的JVM,都是1bit偏向锁+2bit锁标识位,来标识对象状态的。

相关阅读

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值