内存屏障与JVM指令

内存屏障与JVM指令

在硬件层是怎么保证数据的一致性的?MESI协议
老的协议就是总线锁,新的协议就是缓存锁(MESI 等等各种协议) + 总线锁,有新的缓存锁这种协议,还需要总线锁吗?肯定需要,有些数据缓存里没装下或者一个缓存装不下,只能锁总线。
MESI协议: 更改过标记成m这叫Modifued。如果是读享我标记成Exclusive。如果这个内容我读的时候别人也在读就标记成Sharod。如果说这个内容在我读的时候被别的cpu改过就标记成Inbalid,这时候说明我读的数据已经是无效的了。

如何保证特定情况下不乱序?
volatile就保证了有序性。


intel lock:意思就是另外一条指令也能实现有序性,这个是java的汇编指令。
内存屏障:英特尔cpu它主要有3条指令,第一种叫sfence屏障save,第二种是ifence屏障load,第三种是mfence两个都有modify/mix,来保证指令的有序性,有序性指的是什么,就是在特定位置插进去内存屏障,什么叫做内存屏障,你可以认为他就是一个屏障,两方越不过来,屏障两端的顺序不可能会变。

volatile的实现细节
1.字节码层面:加了一个访问符ACC_VOLATILE
2.jvm层面:volatile内存区的读写 都加了屏障。

3.os和硬件层面:

所以volatile所谓的实现细节首先要分不同的层次,它首先写源码时候把它编译完它只是在字节码上也就是class文件上给你加了ACC_VOLATILE这么一个标志。当虚拟机读到这个标志的时候它就会在内存区读写之前都加屏障。加完之后虚拟机和操作系统去执行这个虚拟机程序然后读到这个东西的时候在硬件层面是怎么实现的呢? 在Windows上是用lock指令实现的,但是在Linux上怎么实现,据说有人做过实验。在Linux上实现是上面一个屏障下面一个屏障最后一条lock指令,中间才是才是你的volatile区域。

synchronized实现细节
1.字节码层面:monitorenter和 monitorexit指令。monitorexit退出,它内部是怎么实现的呢,加了两条指令叫monitorenter和monitorexit,有人会说为什么有两个monitorexit,其实就是发现异常之后它会自动退出的意思。同步块synchronized产生一个monitorenter,但是产生异常之后它会自动的帮你退出所以有两条monitorexit指令。
2.jvm层面:这个层面实际上就是C和 C++调用了操作系统提供的同步机制
3.os和硬件层面: X86:lock cmpxchg xxxx
硬件层面实际是lock一条指令,synchronized在字节码层面如果你是方法的话直接加了一个
ACC_SYNCHRONIZED这样一个修饰符,如果你是同步语句块的话就是monitorexit和monitorenter。 在jvm层面当它看到了那些东西之后对应的是C和C++调用了操作系统提供的同步机制是要依赖于硬件cpu的。CPU级别是使用lock指令来实现的。

hanppens-before原则,这是实现Java语言的一个规范,有些指令不允许进行重排,这也是由你的java虚拟机去实现的。

对象的创建过程?
创建一个对象new T() 第一步肯定是要把class loading到内存->第二步就是linking的过程,包括三步1:verification校验 2:preparation把类的静态变量设默认值 3:resolution做一个解析->接下来就是类的初始化把静态变量设为初始值同时执行静态语句块。创建对象然后需要申请内存,成员变量在赋默认值,然后调用构造方法在字节码层面,调用构造方法时候,把成员变量设为初始值,接下来调用构造方法语句super调用父类。

对象在内存中的存储布局?
作为对象的内存布局来讲分为两种,第一种叫普通对象,第二种叫数组对象
普通对象:1.有一个对象头markword 8个字节。2.这个对象他是属于哪个class的,他有一个指针是ClassPointer指针,这个指针指向你要的class对象。3.实例数据,也就是加成员变量还有引用类型。4.Padding对齐,主要是因为算出来正好15个字节,但是作为64位机器,它是按块来读,不是按你的字节来读,他这里有一个对齐他是8的倍数,因此普通对象就是这样。
数组对象:多了一项,1.对象头一样。2.ClassPointer你这个对像数组里装的是哪种类型的东西。3.多了一个数组长度,4个字节。4.数组数据。5.对齐8的倍数。

对象头具体包括什么?

MarkWord里面装的是什么?1.锁定信息两位代表对象有没有被锁定。2. GC的标记,他被回头多少次了分代年龄。

对象如何定位?
当我们new出来一个对象T t = newT();这个小t是怎么找到这个对象的?有两种方式
1、句柄池:通过间接指针,它只第一步把小t指向两个指针,这两个指针其中一个指向对象,另外一个指向t.class,这个就是中间隔了一下
2、直接指针:直接指向对象然后再指向t.class。
他俩没有优劣之分,有的虚拟机实现用第一种有的用第二种,Hotspot用的是第二种,第二种效率比较高直接找到对象,第一种他要找一个指针再找下一个,但是第一种GC的时候效率比较高。

对象怎么分配?
首先new一个对象的时候先往栈上分配,栈上如果能分配下就分配在栈上,然后栈一弹出对象就没了,如果栈上分配不下 ,特别大直接分配到堆内存,老年代。如果不大,首先会进行线程本地分配,线程本地分配能分配下就分配,分配不下找伊甸区然后进行GC的过程,GC过程年龄到了就直接到老年代了,如果年龄不到的话GC来GC去一直到年龄到了为止。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值