1、高速缓存

由来:处理器处理能力原因大于主内存(DRAM)访问速率,为了弥补这个差距,引入了高速缓存。

高速缓存是一种存取速率远比主内存大而容量远比主内存小的存储部件,每一个处理器都有其高速缓存。在引入高速缓存之后,处理器执行读、写操作时就不直接操作主内存,而是通过高速缓存执行的。变量名相当于内存地址,变量值相当于相应内存空间中存储的数据。可以理解为,高速缓存为程序中的数据做了一份对应主内存的副本,但高速缓存的存储容量是非常小的,这些数据并不会一直被高速缓存存储。高速缓存在内部结构相当于一个拉链散列表,包含若干个桶,每个桶又包含若干个缓存条目。

  缓存条目分为三个部分:Tag、Data Block和Flag。Data Block也叫做缓存行,是高速缓存和主内存之间数据交换的最小单元,用于存储从内存中读取的或者准备写入内存的数据。Tag包含了与缓存行中数据相对应的内存地址的部分信息。Flag用于表示相应缓存行的状态。一个缓存行可以存若干个变量的值。

  处理器在执行访问操作时会将相应的内存地址解码为tag、index和offest三部分。index相当于桶编号,用来定位内存地址对应的桶;tag通过与缓存条目的Tag进行比较,定位一个具体的缓存条目;一个缓存条目中存储多个变量,offest是缓存行内的位置偏移,可以定位一个变量在缓存行中存储的起始位置。根据内存地址的解码结果,在高速缓存中找到相应的数据,并且所在缓存条目的Flag表示是有效的,那么这个内存操作就称为缓存命中,否则,则称为缓存未命中。缓存未命中是,处理器会从主内存中加载并存入相应的缓存行中。

  处理器一般都具有多个层次的高速缓存,一级缓存、二级缓存、三级缓存等。越靠近处理器的缓存,存取速率越快,容量越小。Linux系统可有通过lscpu查看高速缓存层次。如下图

2、缓存一致性协议

  当多处理器操作共享变量时就会存在读脏数据和丢失更新的问题,为了解决这个问题,引入里缓存一致性协议。

  MESI(Modified-Exclusive-Shared-Invalid)协议就是一种缓存一致性协议,它实现缓存一致性的思想类似于读写锁,对于同一地址的读操作是并发的,对于同一地址的写操作是独占的。通过一组状态和消息来实现这种控制。

MESI状态:

  • Modified(更改过的,M):该状态表示相应缓存行对包含相应内存地址所做的更新结果数据。因为MESI协议中对写操作的地址是独占的,所以同一时刻,多个处理器上的高速缓存中Tag值相同的缓存条目中,只可能有一个缓存条目处于该状态,且该状态缓存条目的数据一定与主内存中数据不一致。
  • Exclusive(独占的,E):该状态表示相应缓存行包含相应内存地址所对应的副本数据。该状态的缓存行独占了相应内存地址的副本数据,其余处理器中的高速缓存都将不再保留该数据的有效副本,且此时缓存行中的数据和主内存中包含的数据应该是一致的。
  • Shared(共享的,S):该状态表示相应缓存行包含相应内存地址所对应的副本数据。如果一个缓存条目处于该状态,且其他处理器上也存在Tag值与该缓存条目Tag值相同的缓存条目,那么这些缓存条目也一定处于Shared状态。该状态下缓存行中包含的数据与主内存中的数据一致。
  • Invalid(无效的,I):该状态表示相应缓存行中不包含任何内存地址对应的有效副本数据。该状态是缓存条目的初始状态。

MESI消息如下表:

消息名 消息类型 描述
Read 请求 通知其他处理器、主内存当前主内存准备读取某个数据。该消息包含待读取数据的内存地址。
Read Response 相应 该消息包含被请求读取的数据。该消息可能是主内存提供的,也可能是其他高速缓存提供的。
Invalidate 请求 通知其他处理器将其高速缓存中指定内存地址对应的缓存条目的状态设置为I,即删除相应内存地址的副本数据(更改其缓存条目的Flag值)
Invalidate Acknowledge 相应 接收到Invalidate消息的处理器必须回复该消息,以表示删除了其高速缓存上相应的副本数据。
Read Invalidate 请求 该消息是又Read和Invalidate消息组合而成的,用于通知其他处理器当前处理器准备更新一个数据,并请求其他处理器删除其高速缓存中相应的副本数据。接收到该消息的处理器必须回复Read Response和Invalidate Acknowledge消息。
Writeback 请求

该消息包含要写入主内存的数据及其相应的内存地址。

  假设多处理器要对A地址的B数据进行操作,B数据为共享变量。

读操作(简略):

写操作(简略):

3、硬件缓冲区:写缓冲器与无效化队列

  MESI协议在解决缓存一致性问题的同时也引入了等待回复MESI消息的延迟问题,为了减少这种延迟,引入了写缓冲器和无效化队列。

  写缓冲器:是处理器内部一个容量比高速缓存还要小的高速存储部件,每个处理器都有其写缓冲器,其内部可包含若干条目。一个处理器无法读取另一个处理器的写缓冲器上的内容。

  处理器进行写操作时,若缓存条目状态为S,则将写操作相关数据写入写缓冲器中,并发送Invalidate消息。若缓存条目状态为I,则为写未命中,将写操作相关数据写入写缓冲器中,并发送Read Invalidate消息。这样,处理器在将操作相关数据写入写缓冲器就可以认为写操作已完成,即不需等待消息回复就可执行其他指令。而当处理器接收到其他处理器回复的针对同一套缓存条目的所有Invalidate Acknowledge时,会将写缓冲器中相应地址的写操作的结果写入相应的缓存行中,此时写操作相对于本处理器之外的其他处理器而言才算是完成。

  无效化队列:处理器在接收到Invalidate消息后,并不删除消息中指定地址的副本数据,而是将消息存入无效化队列后就回复Invalidate Acknowledge消息,减少了写操作处理器的等待时间。

  写缓冲器和无效化队列又会带来内存重排序和可见性问题。

Java多线程学习笔记之二缓存的更多相关文章

  1. Java多线程学习笔记(二)——Executor,Executors,ExecutorService比较

    Executor:是Java线程池的超级接口:提供一个execute(Runnable command)方法;我们一般用它的继承接口ExecutorService. Executors:是java.u ...

  2. java 多线程学习笔记(二) -- IO密集型任务

    IO密集型是指对IO操作较多的任务.下面以查询一些股票价格任务为例: YahooFinance.java public class YahooFinance { public static doubl ...

  3. Java多线程学习笔记(二)

    三 多线程执行的共享数据和非共享数据: 共享数据:就是每个线程执行的时候共享数据使用,比如这个线程一个为5的数据,减少为4之后,另一个线程执行拿到的数据是4,两个线程执行的数据是共享的. 非共享数据: ...

  4. Java多线程学习笔记(一)——多线程实现和安全问题

    1. 线程.进程.多线程: 进程是正在执行的程序,线程是进程中的代码执行,多线程就是在一个进程中有多个线程同时执行不同的任务,就像QQ,既可以开视频,又可以同时打字聊天. 2.线程的特点: 1.运行任 ...

  5. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

  6. JAVA多线程学习笔记(1)

    JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...

  7. Java NIO 学习笔记(二)----聚集和分散,通道到通道

    目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...

  8. Java多线程学习笔记

    进程:正在执行中的程序,其实是应用程序在内存中运行的那片空间.(只负责空间分配) 线程:进程中的一个执行单元,负责进程汇总的程序的运行,一个进程当中至少要有一个线程. 多线程:一个进程中时可以有多个线 ...

  9. Java多线程学习笔记--生产消费者模式

    实际开发中,我们经常会接触到生产消费者模型,如:Android的Looper相应handler处理UI操作,Socket通信的响应过程.数据缓冲区在文件读写应用等.强大的模型框架,鉴于本人水平有限目前 ...

随机推荐

  1. Netty 核心组件 Pipeline 源码分析(一)之剖析 pipeline 三巨头

    目录大纲: 前言 ChannelPipeline | ChannelHandler | ChannelHandlerContext 三巨头介绍 三巨头编织过程(创建过程) ChannelPipelin ...

  2. AWK工具的用法

    基本格式 awk '{commands}' filename 或者 stdin | awk '{commands}' 以下,均简写为awk '{commands}'的形式 commands的用法 co ...

  3. WPF备忘录(2)WPF获取和设置鼠标位置与progressbar的使用方法

    一.WPF 中获取和设置鼠标位置 方法一:WPF方法 Point p = Mouse.GetPosition(e.Source as FrameworkElement); Point p = (e.S ...

  4. office web app server部署和简单操作

    部署环境:windows server 2012 R2,服务器在AD域中 参考网址: https://msdn.microsoft.com/zh-cn/magazine/jj219455(office ...

  5. Jquery操作样式

    1.CSS(name,value) 修改单个样式 $(function(){ $(".divcontent").css("background","r ...

  6. 选择ORACLE数据库字符集

    如何选择数据库的字符集是一个有争议的话题,字符集本身涉及的范围很广,它与应用程序.客户的本地环境.操作系统.服务器等关系很密切,因此要做出合适的 选择,需要明白这些因素之间的关系.另外对字符集的基本概 ...

  7. 山东省第四届acm解题报告(部分)

    Rescue The PrincessCrawling in process... Crawling failed   Description Several days ago, a beast ca ...

  8. C#转换成Json的方法集

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Te ...

  9. Code Signal_练习题_variableName

    Correct variable names consist only of English letters, digits and underscores and they can't start ...

  10. Java 基础知识总结 3

    13.java类集 类集实际上是一个动态的对象数组,与一般的对象数组不同,类集中的对象内容可以任意扩充. 类集的特征: 1)这种框架是高性能的 2)框架必须允许不同类型的类集以相同的方式和高度互操作方 ...