JVM底层原理篇四:硬件知识 MarkWord 对象在JVM中的定位 创建和内存分布

硬件知识:

存储器的层次结构:
	○ L0:寄存器,速度为1个cpu时间单位,大概是十亿分之一秒
	○ L1:高速缓存,位于CPU核的内部,速度为3-4个cpu时间单位
	○ L2:高速缓存,位于CPU核的内部,速度为10个左右的cpu时间单位
	○ L3:高速缓存,位于CPU的内部,不在核的内部,CPU直接共享的缓存,速度为40-45个cpu时间单位
	○ L4:主存,CPU共享,速度大概是60-80纳秒
	○ L5:磁盘,CPU共享
	○ L6:远程文件存储
	○ 当CPU需要使用一个数据时,会从L1开始往后依次去找,在哪个缓存中找到数据,就从那里开始依次把数据同步回来
缓存行
读取缓存以行(cache line)为基本单位,一行是64字节(byte)
缓存一致性协议
	○ 缓存一致性协议是用来保证数据在线程间一致的协议,也就是同步L1,L2,L3的内容
	○ 老的协议是通过系统总线锁来实现,就是L3到L2的那根线
	○ 因为缓存是以缓存行为单位,一个线程占用总线上锁,其他线程就无法使用,效率比较慢
	○ 新的协议是通过总线锁 + 缓存锁来实现的
	○ 因为有些数据是无法被缓存的,可能跨着多个缓存行,所以必须得有总线锁
	○ 不同的CPU的缓存一致性协议是不一样的,英特尔的CPU用的协议是MESI
	○ MESI就是表示数据四种状态的缩写
		 Modified 我改过
		 Modified 只有我在用
		 Shared 我读的时候别人也在读
		 Invalid 我用的时候别人改过,表示废弃
伪共享
	○ 位于同一个缓存行的两个不同的数据,被两个CPU锁定使用,就会产生互相影响的伪共享问题
	○ 解决办法:
		只要使缓存行对齐,就可以解决这个问题
		在Java中可以在数据的前后各加7个Long,这样就可以保证数据独占一行,在Disruptor中就用到了这样的写法
乱序
	○ 在程序运行过程中,有些指令需要去L3甚至使主存中找数据,效率会非常的慢
	○ 所以在不影响单线程最终一致性的情况下,CPU会进行指令重排,让指令乱序执行,可以提高效率
	○ 但是在特定的情况下,我们并不希望它乱序,否则很容易发生一些无法排查的问题
	○ 比如在对象半初始化的时候,如果产生乱序,提前建立了引用,那其他线程读取这个对象属性就会读取到初始值
	○ WriteCombliningBuffer 合并写
		 在多核CPU中, 写也是会发生乱序的,原因就是合并写
		 WriteCombliningBuffer是在L1和CPU之间一个超高速缓存,简称WCBuffer,合并写
		 在缓存未命中时,CPU就需要把数据写到L2中,但是L2速度很慢,为了不影响CPU执行效率,就会把数据写到WCBuffer中
		 这个缓存只有4个字节,但是速度比L1还要快,每存满4个字节就会向L2中写一次
		 所以在代码测试中,一次性写4个字节比一次性写6个字节效率要更高
	○ 内存屏障
		 内存屏障是解决乱序问题的主要方法
		 CPU都有自己的内存屏障,不同的CPU有不同的屏障指令来保证有序性
		 在英特尔的CPU中主要有三条指令
			 sfence:store|在sfence指令前面的写操作必须在sfence后面的写操作执行前完成
			 lfence:load|在lfence指令前面的读操作必须在lfence后面的读操作执行前完成
			 mfence:moify/mix|在mfence指令前面的读写操作必须在mfence后面的读写操作执行前完成
	○ 在x86的CPU中,保证有序性还可以使用lock指令
	○ lock是原子指令,执行时会锁住内存子系统来确保执行顺序

JVM底层知识

volatile实现
	○ 字节码层面
		 就是添加了一个ACC_VOLATILE的标记
	○ JVM层面
		 在volatile内存区的读写都加内存屏障
		 JVM中的内存屏障和CPU的内存屏障不是一个屏障,只是JVM的实现需要依赖于硬件
		 JVM的内存屏障可以使用CPU的内存屏障实现,也可以使用lock指令来实现
		 在JVM规范中,定义了四个屏障,是Store写和load读的两两组合
	○ OS和硬件层面
		 Windows:直接使用lock指令实现
		 Linux:上下各一条屏障,最后加一条lock指令,中间是volatile的区域
		 硬件层面具体得看CPU是如何保证的有序性和怎么规定的缓存一致性协议
synchronized实现(重量级锁)
	○ 字节码层面:
		 添加了ACC_SYNCHRONIZED标记
		 使用了一个monitorenter和两个monitorexit
		 monitorenter表示监视器进入
		 monitorexit表示监视器退出,一个是正常的退出,一个是遇到异常后的退出
	○ JVM层面
		 升级到重量级锁后,是由C和C++去调用了操作系统的同步机制
	○ OS和硬件层面
		 X86:使用lock指令实现
对象的创建过程
	○ class loading
	○ class linking(verification,preparation,resolution)
	○ class initializing
	○ 申请内存空间
	○ 成员变量赋默认值
	○ 调用构造方法<init>
		 成员变量顺序赋初始值
		 执行构造方法
	○ 建立引用
对象在内存中的存储布局
	○ 对象大小和虚拟机的实现和设置都有关系
	○ 通过命令 java -XX:+PrintCommandLineFlags -version 可以查看相关信息
	○ 普通对象
		 对象头:Markword,占8字节
		 指针:ClassPointer
			 指针压缩后为4字节,不压缩为8字节,默认开启压缩
			 ClassPointers:指的是类对象的指针,也就是实例对象的指针压缩
			 完整参数:-XX:+UseCompressedClassPointers
		 实例数据:成员变量
			 成员变量的指针压缩后为4字节,不压缩为8字节,默认开启压缩
			 Oops:ordinary object pointers,代表的是普通对象指针,也就是成员变量的指针压缩
			 完整参数:-XX:UseCompressedOops
		 8字节对齐:Padding,因为内存是按照块来划分的,为了加快读写效率,所以对象的大小必须是8的倍数
	○ 数组对象
		 相对与普通对象,多了一个数组长度,大小为4字节
	○ hotspot压缩规则
		 4G以下,直接砍掉高32位
		 4G-32G,默认开启内存压缩ClassPointers和Oops
		 32G以上,压缩无效,直接使用64位,所以内存不是越大越好
		 new Object在内存中,占16字节
		 new空数组在内存中占16字节,如果不开启指针压缩的话是24字节
MarkWord对象头(64位,JDK1.8,hotspot)

在这里插入图片描述

	○ 内容被定义在markOop.hpp中,是一个C++的文件,分位五种状态来讨论
	○ 无锁态
		 HashCode,占31位,被调用时才会计算值,全称为identityHashCode
		 分代年龄,占4位,最高只能记录到15岁,因为只有4位
		 锁标志位,占3位,001,代表现在是没有锁的状态
		 剩余的26位没用到
	○ 偏向锁
		 当前线程的ID,占54位,相当于是线程的名牌
		 Epoch,占2位,用于批量重偏向的标记
		 分代年龄,占4位
		 锁标志位,占3位,101,表示偏向锁
		 剩余1位没有用到
		 当一个对象计算过HashCode的值后,就无法再进入偏向锁这个状态,因为HashCode会存储在偏向锁记录线程ID的地方
	○ 轻量级锁
		 锁标志位,占2位,00,表示轻量级锁
		 剩余的62位,是Lock Record的指针,也就是CAS对比数据和替换数据的那把小锁的指针
	○ 重量级锁
		 锁标志位,占2位,10,表示重量级锁
		 剩余62位,是指向内置锁monitor的指针
		 从用户态向内核态申请的锁是由ObjectMonitor管理的
		 ObjectMonitor还存储着重入锁的计数,等待队列,以及当前持有的线程等信息
		 Object中wait和notify方法也要通过ObjectMonitor来实现
	○ GC标记信息
		 锁标志位,占2位,11,代表GC标记
		 剩余62位,是GC在CMS过程中用到的标记信息
对象的定位:
	○ 句柄池:引用会指向句柄池,句柄池中有两个指针,分别指向实例对象和Class对象
	○ 直接指针:引用直接指向实例对象,实例对象自己去指向Class对象
	○ HotSpot中使用的是直接指针,因为GC一些算法关系,所以直接指针的效率会比较高

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值