CPU 缓存基础知识

news2025/1/24 1:43:07

并发编程首先需要简单了解下现代CPU相关知识。通过一些简单的图,简单的代码,来认识CPU以及一些常见的问题。

目录

    • CPU存储与缓存的引入
      • 常见的三级缓存结构
      • 缓存一致性协议
        • MESI协议
        • 缓存行 cache line
      • 通过代码实例认识缓存行的重要性
    • CPU指令的乱序执行
      • 通过代码实例认识到CPU指令乱序执行

CPU存储与缓存的引入

下图描述了存储器金字塔层次结构
在这里插入图片描述

在这里插入图片描述

正因为CPU的计算速度与内存速度的严重不匹配,所以加上了多级缓存,让CPU能执行更多的指令

常见的三级缓存结构

如下图,描述一个有2个CPU且多核心的
在这里插入图片描述

  • L1高速缓存:也叫一级缓存。一般内置在内核旁边,是与CPU结合最为紧密的CPU缓存。一次访问只需要2~4个时钟周期
  • L2高速缓存:也叫二级缓存。空间比L1缓存大,速度比L1缓存略慢。一次访问约需要10多个时钟周期
  • L3高速缓存:也叫三级缓存。部分单CPU多核心的才会有的缓存,介于多核和内存之间。存储空间已达Mb级别,一次访问约需要数十个时钟周期。

当CPU要读取一个数据时,首先从L1缓存查找,命中则返回;若未命中,再从L2缓存中查找,如果还没有则从L3缓存查找(如果有L3缓存的话)。如果还是没有,则从内存中查找,并将读取到的数据逐级放入缓存。如下图所示

在这里插入图片描述

缓存一致性协议

因为现代CPU的架构,所以必然会遇到多个处理器都涉及同一块主内存区域的更改时,这就将导致各自的缓存数据不一致;所以需要采取一定的规范来解决这个问题。如下图所示:

在这里插入图片描述

  • 总线锁是把CPU和内存的通信给锁住了;使得在锁定期间,其它处理器不能操作内存的其它数据,这样开销较大

  • 缓存锁不需锁定总线,只需要"锁定"被缓存的共享对象(实际为:缓存行)即可;接受到lock指令,通过缓存一致性协议,维护本处理器内部缓存和其它处理器缓存的一致性。相比总线锁,会提高CPU利用率。

MESI协议

MESI协议是基于Invalidate的高速缓存一致性协议,并且是支持回写高速缓存的最常用协议之一。

MESI 是指4种状态的首字母。每个缓存行(Cache Line)有4个状态,可用2个bit表示,它们分别是:

状态描述监听任务
M 修改 (Modified)该Cache line有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中。缓存行必须时刻监听所有试图读该缓存行相对就主存的操作,这种操作必须在缓存将该缓存行写回主存并将状态变成S(共享)状态之前被延迟执行。
E 独享、互斥 (Exclusive)该Cache line有效,数据和内存中的数据一致,数据只存在于本Cache中。缓存行也必须监听其它缓存读主存中该缓存行的操作,一旦有这种操作,该缓存行需要变成S(共享)状态。
S 共享 (Shared)该Cache line有效,数据和内存中的数据一致,数据存在于很多Cache中。缓存行也必须监听其它缓存使该缓存行无效或者独享该缓存行的请求,并将该缓存行变成无效(Invalid)。
I 无效 (Invalid)该Cache line无效。

当某个cpu修改缓存行数据时,其它的cpu通过监听机制获悉共享缓存行的数据被修改,会使其共享缓存行失效。本cpu会将修改后的缓存行写回到主内存中。此时其它的cpu如果需要此缓存行共享数据,则从主内存中重新加载,并放入缓存,以此完成了缓存一致性。

缓存行 cache line
  • 程序局部性原理(这里解释为:访问内存或缓存的某个位置,顺带的把紧邻的位置一起读取出来)

    1. 缓存行越大,局部性空间效率越高,但读取时间慢
    2. 缓存行越小,局部性空间效率越低,但读取时间快

常见的缓存行一般64字节

通过代码实例认识缓存行的重要性

import java.util.concurrent.CountDownLatch;


public class Main {

    private static class T {
        public volatile long x;
    }

    public static T[] arr = new T[2];

    static {
        arr[0] = new T();
        arr[1] = new T();
    }

    // 一亿次
    static int FOR_COUNT = 100_000_000;

    public static void main(String[] args) throws Exception{
        CountDownLatch latch = new CountDownLatch(2);

        Thread t1 = new Thread(()->{
            for (int i = 0; i < FOR_COUNT; i ++){
                arr[0].x ++;
            }
            latch.countDown();
        });

        Thread t2 = new Thread(()->{
            for (int i = 0; i < FOR_COUNT; i ++){
                arr[1].x ++;
            }
            latch.countDown();
        });

        final long start = System.nanoTime();
        t1.start();
        t2.start();
        latch.await();
        System.out.println((System.nanoTime() - start) /1_000_000 + " ms");
    }
}

在自己电脑上(2.3 GHz 双核Intel Core i5)跑如上代码要接近3000豪秒了

如上程序是:两个线程分别处理一个对象数组的不同变量,而这个变量是个volatile long x; ,因为数组的2个变量是在同一个缓存行中的,每次修改都修改了同一个缓存行,要有缓存同步操作,所以比较慢。

再看如下程序,只需修改T的定义

private static class T {
    public volatile long p1, p2, p3, p4, p5, p6, p7;
    public volatile long x;
    public volatile long p8, p9, p10, p11, p12, p13, p14;
}

在这里插入图片描述

可以降低到1000毫秒左右,因为数组的两个元素:arr[0].xarr[1].x 不会在一个缓存行中;这样修改用的各自的缓存行,互不影响:

56字节
x(8字节)
56字节
56字节
x(8字节)
56字节

当然使用@Contended(运行加上`-XX:-RestrictContended)是最方便的
在这里插入图片描述

CPU指令的乱序执行

cpu中为了能够让指令的执行尽可能地并行起来,从而发明了流水线技术。但是如果两条指令的前后存在依赖关系,比如数据依赖,控制依赖等,此时后一条语句就必需等到前一条指令完成后,才能开始。cpu为了提高流水线的运行效率,会做出比如:

  1. 对无依赖的前后指令做适当的乱序和调度;
  2. 对控制依赖的指令做分支预测;
  3. 对读取内存等的耗时操作,做提前预读;

这些都可能会导致指令乱序


附: 指令流水线是为提高处理器执行指令的效率,把一条指令的操作分成多个细小的步骤(取指、译码、执行、访问主存、写回),每个步骤由专门的电路完成的方式。举个例子:例如一条指令要执行要经过3个阶段:取指令、译码、执行,每个阶段都要花费一个机器周期,如果没有采用流水线技术,那么这条指令执行需要3个机器周期;如果采用了指令流水线技术,那么当这条指令完成取指后进入译码的同时,下一条指令就可以进行取指了,这样就提高了指令的执行效率。

通过代码实例认识到CPU指令乱序执行

google blog: Memory Reordering Caught in the Act

代码如下:

public class Main {

    static int x, y, a, b;

    public static void main(String[] args) throws Exception{
        int i = 0;
        while (true) {
            x = 0;
            y = 0;
            b = 0;
            a = 0;

            Thread A = new Thread(new Runnable() {
                @Override
                public void run() {
                    a = 1;
                    x = b;
                }
            });

            Thread B = new Thread(new Runnable() {
                @Override
                public void run() {
                    b = 1;
                    y = a;
                }
            });

            A.start();
            B.start();

            A.join();
            B.join();

            i++;
            if(x == 0 && y == 0){
                System.err.println(i + " " + x + " " + y);
                break;
            }
        }
        System.out.println("main end");
    }
}

指令有序的话,理论上不会出现x,y都等于0的情况;如果出现,则可以说明指令乱序

如上程序运行一段时间后(需要耐心等待一下),退出输出如下:

在这里插入图片描述

后续在认识线程安全(可见性,原子性,顺序性)的时候还将复习到此知识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2281161.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

江天科技主要产品销售单价下滑,应收账款、存货周转率大幅下降

《港湾商业观察》廖紫雯 日前&#xff0c;苏州江天包装科技股份有限公司&#xff08;以下简称&#xff1a;江天科技&#xff09;冲击北交所&#xff0c;保荐机构为国投证券。 江天科技主要从事标签印刷产品的研发、生产与销售&#xff0c;公司主要产品包括薄膜类和纸张类的不…

Unity中在UI上画线

在UI中画一条曲线 我封装了一个组件,可以实现基本的画线需求. 效果 按住鼠标左键随手一画. 用起来也很简单,将组件挂到空物体上就行了,红色的背景是Panel. 你可以将该组件理解为一个Image,只不过形状更灵活一些罢了,所以它要放在下面的层级(不然可能会被挡住). 代码 可以…

Cloud Foundry,K8S,Mesos Marathon弹性扩缩容特性对比

一、Cloud Foundry 使用Scaling an Application Using App Autoscaler插件&#xff0c;基于资源使用情况触发简单扩缩容 CPU、内存、Http带宽、延时等 监控这些资源的使用情况决定扩缩容策略&#xff1a;实例是增加还是减少 Instance Limits 限制实例数量范围&#xff0c;定义…

Qt —— 控件属性

一、概述 控件有很多属性&#xff0c;我们学习和整理常见和常用的几个属性&#xff0c;由于所有的控件基本都是继承Widget类的&#xff0c;所以前面会先拿Widget类和常见的控件进行示范。 Qt Designer左侧一长条就是Qt给我们内置好的控件&#xff1a; 二、enabled 状态属性 …

vue+高德API搭建前端Echarts图表页面

利用vue搭建Echarts图表页面&#xff0c;在搭建Echarts图表中&#xff0c;如果搭建地理地形图需要准备一些额外的文件&#xff0c;地理json文件和js文件&#xff0c;js文件目前在网上只能找省一级的&#xff0c;json文件有对应的省市县&#xff0c;js文件和json文件对应的也是不…

Gartner发布2025年网络治理、风险与合规战略路线图

新型网络风险和合规义务&#xff0c;日益成为网络治理、风险与合规实践面临的问题。安全和风险管理领导者可以参考本文&#xff0c;实现从被动、专注于合规的方法到主动、进一步自动化方法的转型。 主要发现 不断变化的监管环境和不断扩大的攻击面&#xff0c;使企业机构难以实…

Redis 集群模式入门

Redis 集群模式入门 一、简介 Redis 有三种集群模式&#xff1a;主从模式、Sentinel 哨兵模式、cluster 分片模式 主从复制&#xff08;Master-Slave Replication&#xff09;: 在这种模式下&#xff0c;数据可以从一个 Redis 实例&#xff08;主节点 Master&#xff09;复…

查看电脑或笔记本CPU的核心数方法及CPU详细信息

一、通过任务管理器查看 1.打开任务管理器 可以按下“Ctrl Shift Esc”组合键&#xff0c;或者按下“Ctrl Alt Delete”组合键后选择“任务管理器”来打开。 2.查看CPU信息 在任务管理器界面中&#xff0c;点击“性能”标签页&#xff0c;找到CPU使用记录区域&#xff0c…

光学遥感显著性目标检测2023-2024论文学习

GRSL 2023&#xff1a; Attention-Aware Three-Branch Network for Salient Object Detection in Remote Sensing Images 基于encoder-decoder框架&#xff0c;提出了一系列缝合模块&#xff0c;GCA&#xff0c;FDUC&#xff0c;MSDC&#xff0c;RA。 GRSL 2023&#xff1a;OR…

Kubernetes 集群中安装和配置 Kubernetes Dashboard

前言 上篇成功部署Kubernetes集群后&#xff0c;为了方便管理和监控集群资源&#xff0c;安装Kubernetes Dashboard显得尤为重要。Kubernetes Dashboard 是一个通用的、基于 Web 的 UI&#xff0c;旨在让用户轻松地部署容器化应用到 Kubernetes 集群&#xff0c;并对这些应用进…

2025西湖论剑-babytrace

前言 就做了下题目&#xff0c;pwn1/3 都是签到&#xff0c;pwn2 后面绕 ptrace 有点意思&#xff0c;简单记录一下 漏洞分析 子进程中的读/写功能没有检查负数的情况&#xff0c;存在越界读写&#xff1a; void __fastcall get_value(__int64 *int64_arr) {__int64 ll; //…

HarmonyOS Next 应用UI生成工具介绍

背景 HarmonyOS Next适配开发过程中难买难要参考之前逻辑&#xff0c;但是可能时间较长文档不全&#xff0c;只能参考Android或iOS代码&#xff0c;有些逻辑较重的场景还可以通过AI工具将Android 的Java代码逻辑转成TS完成部分复用。对于一些UI场景只能手动去写&#xff0c;虽…

计算机网络 (56)交互式音频/视频

一、定义与特点 定义&#xff1a;交互式音频/视频是指用户使用互联网和其他人进行实时交互式通信的技术&#xff0c;包括语音、视频图像等多媒体实时通信。 特点&#xff1a; 实时性&#xff1a;音频和视频数据是实时传输和播放的&#xff0c;用户之间可以进行即时的交流。交互…

【深度学习】Java DL4J 2024年度技术总结

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

考研408笔记之数据结构(三)——串

数据结构&#xff08;三&#xff09;——串 1. 串的定义和基本操作 本节内容很少&#xff0c;重点是串的模式匹配&#xff0c;所以对于串的定义和基本操作&#xff0c;我就简单提一些易错点。另外&#xff0c;串也是一种特殊的线性表&#xff0c;只不过线性表是可以存储任何东…

Spring Data JPA使用基础教程

文章目录 Spring Data JPA使用基础教程一、引言二、环境搭建1、添加依赖2、配置数据库 三、核心组件1、实体类2、Repository 接口 四、使用示例1、基本操作1.1、保存数据1.2、查询数据1.3、更新数据1.4、删除数据 2、自定义查询 五、最佳实践1. **合理使用懒加载与急加载**2. *…

到华为考场考HCIE的注意事项和考试流程

大家好&#xff0c;我是张同学&#xff0c;来自成都职业技术学院2021级计算机网络专业。最近成功通过了 Datacom HCIE 考试&#xff0c;在这里和大家分享一下我的经验。 考证契机 在母校的培养下&#xff0c;我接触到ICT这个行业&#xff0c;打好了基础&#xff0c;开始了成…

STM32 ST7735 128*160

ST7735 接口和 STM32 SPI 引脚连接 ST7735 引脚功能描述STM32 引脚连接&#xff08;示例&#xff0c;使用 SPI1&#xff09;SCLSPI 时钟信号 (SCK)PA0(SPI1_SCK)SDASPI 数据信号 (MOSI)PA1 (SPI1_MOSI)RST复位信号 (Reset)PA2(GPIO 手动控制)DC数据/命令选择 (D/C)PA3 (GPIO 手…

大华相机DH-IPC-HFW3237M支持的ONVIF协议

使用libONVIF C库。 先发现相机。 配置 lib目录 包含 编译提示缺的文件&#xff0c;到libonvif里面拷贝过来。 改UDP端口 代码 使用msvc 2022的向导生成空项目&#xff0c;从项目的main示例拷贝过来。 CameraOnvif.h #pragma once#include <QObject> #include &l…

JavaWeb过滤器和监听器实现网页计数功能

过滤器用于在请求到达Servlet之前或响应返回给客户端之前对请求或响应进行预处理或后处理操作&#xff0c;监听器用于监听Web应用中的事件。 实现网页计数功能。要完成两项计数&#xff1a; 第一&#xff0c;本网页历史访问人数&#xff1b; 第二&#xff0c;本站当前在线用户…