1. 概述

在执行程序时, 为了提高性能, 编译器和处理器常常会对指令做重排序. 为了实现某些功能有时会禁止某些重排序, 由此引入了内存屏障.

2. 重排序

重排序虽然可以提高程序性能, 但是编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序. 即: 编译器和处理器在重排序时, 会遵
守数据依赖性.

这里说的数据依赖性仅针对单个处理器中执行的指令序列和单个线程中执行的操作, 不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑.

2-1. as-if-serial语义

as-if-serial语义的意思是: 不管怎么重排序(编译器和处理器为了提高并行度), (单线程)程序的执行结果不能被改变. 编译器、runtime和处理器都必须遵守as-if-serial语义.

为了遵守as-if-serial语义, 编译器和处理器不会对存在数据依赖关系的操作做重排序, 因为这种重排序会改变执行结果. 但是, 如果操作之间不存在数据依赖关系, 这些操作就可能被编译器和处理器重排序.

2-2. 重排序的种类

  1. 编译器优化的重排序: 编译器在不改变单线程程序语义的前提下, 可以重新安排语句的执行顺序.
  2. 指令级并行的重排序: 现代处理器采用了指令级并行技术(Instruction-Level Parallelism, ILP)来将多条指令重叠执行. 如果不存在数据依赖性, 处理器可以改变语句对应机器指令的执行顺序.
  3. 内存系统的重排序: 由于处理器使用缓存和读/写缓冲区, 这使得加载和存储操作看上去可能是在乱序执行.

2-3. 从Java源代码到最终实际执行的指令序列, 会分别经历下面3中重排序.

源代码 -> 1:编译器优化重排序 -> 2:指令级并行重排序 -> 3:内存系统重排序 -> 最终执行的指令序列

其中1属于编译器重排序, 2和3属于处理器重排序. 这些重排序可能会导致多线程程序出现内存可见性问题. 对于编译器, JMM编译器重排序规则会禁止特性类型的编译器重排序(并不是所有的编译器重排序都要禁止); 对于处理器重排序, JMM的处理器重排序规则会要求Java编译器在生成指令序列时, 插入特性类型的内存屏障(Memory Barriers, Intel称之为Memory Fence)指令, 通过内存屏障指令来禁止特定类型的处理器重排序.

JMM属于语言级的内存模型, 它确保在不同的编译器和不同的处理器平台之上, 通过禁止特性类型的编译器重排序和处理器重排序, 为程序员提供一致的内存可见性保证.

3. 内存屏障类型

现代的CPU使用写缓冲区临时保存向内存写入的数据. 写缓冲区可以保证指令流水线持续运行, 它可以避免由于处理器停顿下来等待向内存写入数据而产生的延迟. 同时, 通过以批处理的方式刷新写缓冲区, 以及合并写缓冲区中对同一内存地址的多次写, 减少对内存总线的占用. 虽然写缓冲区有这么多好处, 但是每个处理器的写缓冲区仅仅对它所在的处理器可见. 这个特性会对内存操作的执行顺序产生重要的影响: 处理器对内存的读/写操作的执行顺序. 不一定与内存实际发生的读写操作顺序一致.

写缓冲区仅对自己的处理器可见, 它会导致处理器执行内存操作的顺序可能会与内存实际的操作执行顺序不一致. 由于处理器都会使用写缓冲区, 因此现代处理器都会允许对写-读操作进行重排序.

3-1. 处理器的重排序规则

可以发现常见的处理器都允许StoreLoad重排序; 常见的处理器都不允许对存在数据依赖的操作做重排序. SPARC-TSO和X86拥有相对较强的处理器内存模型, 它们仅允许对写-读操作做重排序(因为它们都使用了写缓冲区).

3-2. 内存屏障类型表

为了保证内存可见性, Java编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序.

StoreLoad Barriers是一个"全能型"的屏障, 它同时具有其他3个屏障的效果. 现代的多处理器大多支持该屏障(其他类型的屏障不一定被所有处理器支持). 执行该屏障开销会很昂贵, 因为当前处理器通常要把写缓冲区中的数据全部刷新到内存中(Buffer Fully Flush).

4. 总结

重排序可以提高性能, 但是重排序可能会导致内存可见性问题, 问了解决这个问题, 编译器在生成字节码的时候会插入特定类型的内存屏障来禁止重排序, 保证多线程下的内存可见性.

JMM中的重排序及内存屏障的更多相关文章

  1. J.U.C JMM. pipeline.指令重排序,happen-before(续)

    前面已经介绍硬件平台Cache Coherence问题和解决办法,下面来看看Java虚拟机平台的相关知识.硬件平台处理器,高速缓存,主存之间的交互关系如下: Java内存模型(JMM)         ...

  2. J.U.C JMM. pipeline.指令重排序,happen-before

    pipeline: 现在的CPU一般采用流水线方式来执行指令.一个指令执行周期被分成:取值,译码,执行,访存,写会,更新PC若干阶段.然后,多条指令可以同时存在于流水线中,同时被执行,来提高系统的吞吐 ...

  3. Jvm 中的 重排序、主存、原子操作

    一.重排序 好处:重排序可以提升性能,避免在一个耗时很长的指令在“执行”阶段呆很长时间,而导致后续的指令都卡在“执行”之前的阶段上. 坏处:重排序对多线程的影响 class ReorderExampl ...

  4. JS中数组重排序方法

    在数组中有两个可以用来直接排序的方法,分别是reverse()和sort().下面通过本文给大家详细介绍,对js数组重排序相关知识感兴趣的朋友一起看看吧 1.数组中已存在两个可直接用来重排序的方法:r ...

  5. Javascript中数组重排序方法详解

    在数组中有两个可以用来直接排序的方法,分别是reverse()和sort().下面通过本文给大家详细介绍,对js 数组重排序相关知识感兴趣的朋友一起看看吧. 1.数组中已存在两个可直接用来重排序的方法 ...

  6. J.U.C JMM. pipeline.指令重排序,happen-before(续MESI协议)

    缓存(Cache)       CPU的读/写(以及取指令)单元正常情况下甚至都不能直接访问内存——这是物理结构决定的:CPU都没有管脚直接连到内存.相反,CPU和一级缓存(L1 Cache)通讯,而 ...

  7. Java内存访问重排序笔记

    >>关于重排序 重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段. 重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境. > ...

  8. JVM内存模型、指令重排、内存屏障概念解析

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

  9. JVM内存模型、指令重排、内存屏障概念解析(转载)

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

随机推荐

  1. 剑指Offer 44. 翻转单词顺序列 (字符串)

    题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,"st ...

  2. 5.移动终端App测试点归纳

    以下所有测试最后必须在真机上完整的执行. 1 安装.卸载测试 1.1 在真机上.第三方软件(xy苹果助手.91.安卓助手)的安装与卸载 1.2 安装在手机卡上 或 SD卡上 (不同的IOS和安卓版本) ...

  3. apache kylin总结

    去年12月挖的坑,今天找时间填上.update:20190119 一.kylin架构 核心是预计算,在此架构上做了一些优化.计算结果存储在Hbase,对Hive等查询转换为Hbase的Scan,提高速 ...

  4. scrapy框架的日志等级和请求传参

    日志等级 请求传参 如何提高scrapy的爬取效率 一.Scrapy的日志等级 - 在使用scrapy crawl spiderFileName运行程序时,在终端里打印输出的就是scrapy的日志信息 ...

  5. Windows下 安装Jenkins 并发布至docker 实战

    网上的教程基本都是Linux系统下安装Jenkins,并且发布到Linux系统下的docker中, 于是打算在全部windows的环境中,完成Jenkins的持续集成功能. 环境: 服务器环境: wi ...

  6. 洛谷P1605:迷宫(DFS)

    题目背景 迷宫 [问题描述] 给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过.给定起点坐标和终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案.在迷宫中移动有上下左右 ...

  7. install svn server in Ubuntu

    1. #安装服务 apt-get install subversionapt-get install libapache2-svnapt-get install apache2apt-get inst ...

  8. Win下更新pip出现OSError:[WinError17]与PerrmissionError:[WinError5]及解决

    环境:Win7 64位,python3.6.0 我在准备用pip装东西的时候,在cmd里先更新了一下pip,大概是9.0.1更新到9.0. 尝试更新pip命令: pip install --upgra ...

  9. 学习笔记TF036:实现Bidirectional LSTM Classifier

    双向循环神经网络(Bidirectional Recurrent Neural Networks,Bi-RNN),Schuster.Paliwal,1997年首次提出,和LSTM同年.Bi-RNN,增 ...

  10. Android related

    The build env. ensure that your computer’s BIOS is set up to support Intel’s virtualization extensio ...