重排序和内存屏障指令

Posted coderDu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重排序和内存屏障指令相关的知识,希望对你有一定的参考价值。

参考及相关文献:

英语好有时间的同学,建议瞄一眼此博文去读参考文献内容。

1. 写缓冲区

现在的处理器使用写缓冲区临时保存写入内存的数据,写缓冲区的优点是:

  1. 可以保证指令持续运行,避免由于处理器等待向内存写入而产生的停顿延迟
  2. 批处理的方式刷新写缓冲区,及合并写缓冲区中对同一个内存地址的多次写操作,可以减少对内存总线的占用

由于写缓冲区仅仅对自己的处理器可见,因此会导致各个处理器对内存操作的顺序可能与内存实际的操作(即受到数据修改后的值并做改变的顺序)执行顺序不一致。。示意如下:
技术分享图片

现代处理器都是用了缓冲区,并且都允许对写-读Store-Load操作重排序:
技术分享图片

2. java内存模型的内存屏障指令

为了禁止处理器特定类型的重排序(通常指x86平台的Store-Load),java编译器通过在适当的(与代码语义一直)的位置插入内存屏障指令来禁止特定类型的处理器重排序。四类内存屏障指令如下:


1. Load-Load Barrier:
    示例:Load1;LoadLoad;Load2
    解释:保证装载动作Load1早于Load2即以后所有的Loadn动作,但是对于屏障前后的Store操作并无影响;

2. Store-Store Barrier:
    示例:Stroe1;StroeStore;Store2
    解释:确保Stroe1动作将数据刷新到内存(使得数据对其他处理器可见),早于Store2及其以后所有Storen动作的执行。同理对Loadn操作无影响;

3. Load-Stroe Barrier:
    示例:Load1;Load-Stroe;Store2:
    解释:屏障指令之前的所有Load操作都早于屏障之后所有指令的装载动作(刷新数据到主存);

4. Store-Load barriers——全能型,
    1)保证屏障之前的所有访问操作完成之后才执行屏障之后的内存访问操作——所谓访问操作包括读取和装载。

[注]:注意Store-Load是全能型的,会屏蔽前后所有类型指令的重排

3. volatile内存语义的实现

java内存模型为了实现volatile可见性和禁止指令重排两个语义,使用如下内存屏障插入策略:

  1. 每个volatile写操作前边插入Store-Store屏障,后边插入Store-Load(全能)屏障;

  2. 每个volatile读操作前边插入Load-Load屏障和Load-Stroe屏障;

技术分享图片
如图所示:写volatile屏障指令插入策略可以保证在volatile写之前,所有写操作都已经刷新到主存对所有处理器可见了。其后全能型屏障指令为了避免写volatile与其后volatile读写指令重排序。

技术分享图片

volatile时,会在其后插入两条指令防止volatile读操作与其后的读写操作重排序。

4.单利模式中的内存屏障
public class Singleton {
    private static volatile Singleton singleton=null;

    private Singleton(){}

    public static Singleton getSingleton(){
        if(singleton==null)
        //此处读取singleton,后边加入load-load和load-store屏障
        {
            synchronized (Singleton.class){
                if(singleton==null)
                //此处读取singleton,后边加入load-load和load-store屏障
                {
                    //此处写singleton:加入Store-Store屏障
                    singleton=new Singleton();
                    //fixme 此处写singleton:加入Store-Load屏障,
                    // fixme 此处屏障防止了第二个线程对主存数据singleton读取早于此前线程创建singleton并装载进主存之前
                }
            }
        }
        return singleton;
    }
}



以上是关于重排序和内存屏障指令的主要内容,如果未能解决你的问题,请参考以下文章

CPU运行时优化(高速缓存指令重排内存屏障等)

volatile关键字?MESI协议?指令重排?内存屏障?这都是啥玩意

Android-JMM内存模型-指令重排-Happens-Before原则-volatile-lock指令-内存屏障

Android-JMM内存模型-指令重排-Happens-Before原则-volatile-lock指令-内存屏障

内存屏障

内存屏障