内存屏障相关理解

 
我们都知道Volidate的作用主要有两个:1 解决共享变量的可见性问题  2 防止指令重排序
 
 
一、在多核CPU下,计算机的现状与问题,以及如何使用MESI协议,内存屏障来解决问题的
    串联概念:引入多核CPU、寄存器、高速缓存,StoreBuffer、主存等概念
   一台计算机核心组件为CPU、内存、IO设备,但是这三者之间的速度相差很大,为了解决三者处理速度的差异,计算机做了很多优化
  1.   CPU增加了高速缓存,增加CPU获取数据的速度
  2. 操作系统引入进程和线程,然后对CPU时间进行切片,当时间片轮转的时候执行不同的进程和线程,增加CPU的使用率
  3. 增加指令优化,以便更合理的使用高速缓存
优化以后的计算机中CPU和缓存之间的关系如下图:

 

 

CPU和主存之间引入了高速缓存,CPU计算的时候执行流程为:
  1. CPU计算需要的数据从主存中加载到高速缓存中
  2. CPU计算数据从高速缓存中直接读取,然后计算
  3. 计算完成后将数据写回高速缓存
  4. 数据从高速缓存写回主存
 
当每个CPU运行不同的线程,每个线程都会缓存一份计算所需要的数据,当有多个线程同时对一个共享数据进行更改时候,就会出现数据不一致的问题
为了解决数据不一致问题引入了MESI协议(不同CPU协议不同),大概的流程为:
场景:CPU两个核:Core1 ,Core2 ,同时用到共享变量 v1,流程为
  1.  Core1 对数据v1进行了修改后,发送一个信号给Core2使其缓存v1失效,并且将v1写回到主存中
  2. Core2使用共享变量v1的时候发现缓存失效,则从主存中加载共享变量
 
这样解决了多核CPU共享数据的一致性问题,但是每次发送同步信号给其他Core的时候是同步的,进一步优化引入了StoreBuffer,进行异步处理
加入异步处理的时候,现在的流程变成这个样子:
 
  1.  Core1 对数据v1进行了修改后,异步发送一个信号给Core2使其缓存v1失效,并且数据放到StoreBuffer中,Core1可以继续执行其它指令
  2.  Core2使用共享变量v1的时候发现缓存失效,则从主存中加载共享变量
 
新问题:异步的时候,如果Core2一直很繁忙,则数据就不能设置为失效,也不能同步到主存中,这时候引入内存屏障,当Core1发现对应的变量使用内存屏障修饰,则强制将数据刷新到主存中,使所有的Core对数据可见。
 
 
二、volidate中如何使用内存屏障来解决问题的
 
        Volidate关键字修饰的共享变量,在字节码中会生成一个Lock指令,当Jvm进行解析的时候会判断是否为Volidate修饰,如果是volidate修饰则调用OrderAccess::storeload();来进行内存屏障设置,内部使用fence
 
三、可见性问题本质
    可见性本质是缓存和指令重排序导致的,
    Java层面上的JMM,提出了一些关键字和原则很好的解决可见性问题:如volidate和synchronize
 
 
四、主要参考
 
 
五、idea查看class编译后的字节码的插件
 
 
1)查看java编译后的字节码:idea插件jclasslib
 
2)查看java字节码JDK插件 hsdis-amd64.dll
       使用:下载的dll放到jdk的Java\jdk1.8.0_73\jre\bin目录中
      启动方法中添加:  -server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*Bar.sum
 
 
 
 
 
 
 
 
 
posted @ 2020-10-29 16:11  码来  阅读(275)  评论(0编辑  收藏  举报