CPU缓存一致性协议MESI

CPU缓存一致性协议MESI

  • 引入
    • 1、一条Java指令在JVM和CPU中的执行过程:
    • 2、总线锁
  • 一、多核CPU多级缓存一致性协议MESI
    • 1、简介
    • 2、MESI协议缓存状态
  • 二、volatile与MESI的关系
  • 三、缓存行伪共享
    • 1、介绍
    • 2、解决方法
  • 四、MESI优化和他们引入的问题
    • 1、问题产生原因
    • 2、解决方法

引入

1、一条Java指令在JVM和CPU中的执行过程:

CPU缓存一致性协议MESI_第1张图片

2、总线锁

总线锁就是在总线上加锁,早期还没有多级缓存,所以就出现了CPU寄存器直接访问主存的情况,那么就可能会出现两个CPU同时访问一个变量的情况,如果两个CPU同时对这个变量进行写的操作,那么肯定就会出现问题,所以这个时候就出现了总线锁,同一时间的时候只能有一个CPU去访问这个变量。而现在我们的CPU大多数是多核多CPU的,如果仍然采用总线锁的话,就只能发挥单CPU单核的性能,所以就出现多核CPU多级缓存一致性协议MESI解决方案。

一、多核CPU多级缓存一致性协议MESI

1、简介

现在的计算机一般都是多CPU多核的,所以就会出现多个CPU或者多个核在同一时间访问同一个变量的情况,缓存一致性协议就是来解决当多个核同时对一个变量进行操作的时候,保证数据一致性的问题。

2、MESI协议缓存状态

我们都知道,缓存的存储数据单位为数据行。
小插曲:64位操作系统的缓存行一般占64byte,MESI缓存一致性就是根据缓存行来的,如果一个对象的占用空间大于64字节,那么就不能保证它的原子性了,这个时候就得从缓存一致性升级到总线锁了。

CPU缓存一致性协议MESI_第2张图片
M 修改 (Modified):代表缓存行里面的数据已经被修改了,后续会写到内存中。
E 独享、互斥 (Exclusive):代表该数据只被该CPU或者该核缓存,不存在多个CPU或者多个核同时操作的情况。
S 共享 (Shared):代表该数据被多个CPU或者多个核缓存,存在多个CPU或者多个核同时操作的情况。
I 无效 (Invalid):代表该缓存行里面的数据已经失效了,也就是被其它CPU或者核已经修改掉了。

二、volatile与MESI的关系

(1)一个变量加上volatile时,从Java的汇编语言中我们可以看到在其变量前面多加了一个**#lock**;而这个lock指令会将写入系统内存中;这时就触发了MESI缓存一致性协议,使得其他CPU里缓存了该内存地址的数据无效,则体现了可见性;同时提供内存屏障功能,使得lock前后指令不能重排序,这体现了有序性;
(2)volatile关键字是java语言层面给出的保证,MSEI协议是多核cpu保证cache一致性(后面会细说这个一致性)的一种方法,两者没有必然的联系
在这里插入图片描述

三、缓存行伪共享

1、介绍

CPU缓存系统中是以缓存行(cache line)为单位存储的。目前主流的CPU Cache 的 Cache Line 大小都是64Bytes。在多线程情况下,如果需要修改“共享同一个缓存行的变 量”,就会无意中影响彼此的性能,这就是伪共享(False Sharing)。

下面举个例子:现在有2个long 型变量 a 、b,如果有t1在访问a,t2在访问b,而a与b刚好在同一个 cache line中,此时t1先修改a,将导致b被刷新!

2、解决方法

Java8中新增了一个注解:@sun.misc.Contended。加上这个注解的类会自动补齐缓存行,需要注意的是此注解默认是无效的,需要在jvm启动时设置 -XX:- RestrictContended 才会生效,这样的话我们的一个变量就占一个缓存行了。

四、MESI优化和他们引入的问题

1、问题产生原因

缓存的一致性消息传递是要时间的,这就使其切换时会产生延迟。当一个缓存被切换状态时其他缓存收到消息完成各自的切换并且发出回应消息这么一长串的时间中CPU都会等待所有缓存响应完成。可能出现的阻塞都会导致各种各样的性能问题和稳定性问题。

2、解决方法

当我们CPU修改了一个变量之后,会将它放进一个叫**Store Bufferes(存储缓存)**中,然后再去通知其它的用到了该变量的CPU,其它用到了该变量的CPU收到通知后,会将自己的备份数据放到一个特殊队列中(失效队列),然后立刻发送给修改该变量的CPU一个通知,修改变量的CPU在收到通知之后,会在合适的时间将数据从Store Bufferes 中写到主存中去,其它的CPU先从 Store Bufferes 里面获取数据,等到合适的时间,再将失效队列的数据丢弃掉。

Store Bufferes的风险

简单来说,将会出现重排序问题

(1)就是处理器会尝试从存储缓存(Store buffer)中读取值,但它还没有进行提交。这个的解决方案称为Store Forwarding,它使得加载的时候,如果存储缓存中存在,则进行返回。
(2)保存什么时候会完成,这个并没有任何保证。

你可能感兴趣的:(JAVA并发编程,缓存,java)