内卷老员工之三级缓存和伪共享
cpu三级缓存与伪共享
cpu三级缓存
- cpu共有L1 cache、L2 cache、L3 cache三级缓存,速度由高到低。其中L1与L2为cpu核心内共享,L3为所有cpu共享。
- L1、L2、L3缓存的速度从高到底,容量从低到高。因此当cpu读取数据时,都是从L1缓存开始读取,如果没法命中再依次向外读取,最后在内存中读取。以这种方式可以大大的提高响应时间,提高系统的性能。
cpu的缓存一致性
- cpu的缓存会在适当的时刻被刷新到主内存中,而利用缓存一致性的方法,会使得其他cpu看到当前cpu缓存中修改刷新到主存中的数据。
- 数据可能一直不被刷新到主存而是保存在cpu的缓存中,一直到其他数据需要缓存中的信息,才会将cpu的缓存刷新到主存中。只要cpu能够获取到数据,从缓存中或从主存中并没有什么影响。
- cpu缓存一致性自然也会对性能有所影响,但很明显,这种方式比直接在主存中存取的性能要好的多。
伪共享
- 当不同cpu操作的不同变量,存储在同一cpu缓存行中时,就会产生伪共享问题(False sharing)。当一个线程修改其中一个变量时,整个缓存行在另一个cpu中的缓存将失效,需要重新读取无效缓存行的内容,也就是产生了伪共享。
缓存行与缓存行失效
- 当cpu从主存中读取数据时,不会一次只读取一个字节,而是会一次性读取64字节以寻求高效。而一次性读取的64字节也就是一个缓存行。一个缓存行由多个字节组成,也就是会同时存储多个变量。如果多个cpu同时访问同一缓存行的多个变量,则发生了伪共享。
- 当缓存行中变量发生更改时,其他cpu所读取的缓存行数据即变为脏数据,需要从主存中重新读取,而这一过程中cpu无法读取到数据,缓存行失效。
伪共享产生的性能问题
- 当缓存行中的数据由于被其他cpu修改而变为无效,则需要刷新无效的缓存行。因此cpu需要读取缓存中的数据就需要等待缓存行数据刷新,这一过程中就会产生性能损失,cpu在这一时间区间内只能执行更少的指令。
- 伪共享意味着两个cpu不停的对同一缓存行的内容进行写入,导致缓存行反复失效,等待数据刷新,cpu处理的效率就会产生明显的影响。
- 伪共享的解决方案一般是利用数据结构,保证变量存储在不同的缓存行中。
伪共享代码举例
private static volatile long[] a = new long[16];
public static void main(String[] args) throws InterruptedException {long start = System.currentTimeMillis();Thread t1 = new Thread(() -> {for (int i = 0; i < 1000000000; i++) {a[0] = i;}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000000000; i++) {a[1] = i;}});t1.start();t2.start();t1.join();t2.join();System.out.println(System.currentTimeMillis() - start);long start1 = System.currentTimeMillis();Thread t3 = new Thread(() -> {for (int i = 0; i < 1000000000; i++) {a[2] = i;}});Thread t4 = new Thread(() -> {for (int i = 0; i < 1000000000; i++) {a[14] = i;}});t3.start();t4.start();t3.join();t4.join();System.out.println(System.currentTimeMillis() - start1);
}
- 由于long型所占空间为8个字节,因此可以保证a[2]和a[14]位于不同缓存行中。a[0]和a[1]相邻大概率位于同一缓存行中。经过运行可以轻易发现,伪共享的a[0]和a[1]运行时间明显大于位于不同缓存行的a[2]和a[14];
面对伪共享问题的解决方案
- 使用注解@Contented
- 该注解使用空对象填充的方式,保证变量可以不位于同一缓存行中,可以用于类和变量字段,同时可以设置大小。
- 通过数据结构修改
- 通过数据结构的方式,也就是经过数据结构的调整,让相邻变量不位于同一缓存行中,防止伪共享对性能的浪费。
- 使用disruptor框架
- disruptor采用long变量填充的方式,保证不同的变量一定位于不同的缓存行之中,以此提高性能。
后记
- 千古兴亡多少事?悠悠。不尽长江滚滚流。
内卷老员工之三级缓存和伪共享相关推荐
- 内卷老员工之java内存模型
java内存模型 java内存模型都不知道,如何内卷老员工 Java 内存模型指 Java 虚拟机如何使用计算机的内存. Java 内存模型指定不同线程如何以及何时可以看到其他线程写入共享变量的值,以 ...
- 内卷老员工之java内存模型的happens-before原则
java内存模型的happens-before原则 前言 happens-before原则是指线程本地内存与主内存的同步关系,只有满足happens-before原则的情况下,线程内存发生变化时,才会 ...
- Spring是如何利用“三级缓存“巧妙解决Bean的循环依赖问题
前言 循环依赖:就是N个类循环(嵌套)引用. 通俗的讲就是N个Bean互相引用对方,最终形成闭环.用一副经典的图示可以表示成这样(A.B.C都代表对象,虚线代表引用关系): 注意:其实可以N=1,也就 ...
- 打造新老员工双赢机制变对立为统一
在一个高效的组织里面,组织内部人员的流动就像血液流动一样,过快或者过慢都不好,不断的新生力量有利于去帮助组织去更好的成长和创新发展.但是就像输血会发生排异反应一样,新来的员工会在组织内部有一个适应过程 ...
- Spring三级缓存解决循环依赖
1. 前言 循环依赖:就是N个类循环(嵌套)引用. 通俗的讲就是N个Bean互相引用对方,最终形成闭环.用一副经典的图示可以表示成这样(A.B.C都代表对象,虚线代表引用关系): 其实可以N=1,也就 ...
- 缓存一致性协议和CPU缓存架构(MESI协议)、伪共享
目录 简介 CPU高速缓存 为什么要有CPU高速缓存 局部性原理 缓存一致性 缓存一致性的要求 总线窥探 工作原理 窥探协议 一致性协议 MESI协议 总线事务 总线仲裁 总线锁定 缓存锁定 伪共享问 ...
- java 缓存行填充_缓存伪共享问题以及解决方案缓存行填充
缓存伪共享 共享对象存在同一个缓存中,由于MESI协议,一个对象中一些不需要改变的属性因为其他改变的属性,导致整个对象的缓存进入到M被修改状态. 目前的CPU是通常按照32或者64字节的缓存行(Cac ...
- 乐视成了反内卷之王:员工过上了没有996的神仙日子!
整理 | 于轩 责编 | 张红月 出品 | 程序人生(ID:coder_life) 提到乐视,你会想到"下周回国贾跃亭"还是Logo上的"乐视欠122亿&qu ...
- 大厂内卷:蚂蚁集团员工关怀再次升级。测试要如何才能进入大厂?
12 月 12 日消息,近日有一份蚂蚁集团的内部邮件曝光,显示蚂蚁集团所有大陆员工自 2022 年 1 月 1 日起将施行新的员工关怀政策,包含 5 项福利,不仅有住房补贴.带薪年假.加班.打车报销以 ...
最新文章
- 闲鱼异地多活架构设计与实现
- 提取so文件的特征值
- MFC隐藏和显示一个控件的方法
- 视频直播:Windows中各类画面源的截取和合成方法总结
- 快速入门PyTorch(2)--如何构建一个神经网络
- MVC3、如何应用EntityFramework 连接MySql 数据库
- 2020年全球激光雷达行业竞争格局分析,技术路线正处于快速发展迭代阶段「图」
- vs2017 社区版
- css3直线运动_纯css3动画--边框线条动画
- hexo之icarus主题的美化修改以及简单的SEO配置
- 计划预算(PV)、实际完成工作预算(EV)、实际成本(AC)
- QCon演讲实录|基于 KAITIAN 的前端工程研发模式变革
- Ubuntu查找软件源
- 赛灵思FPGA功耗实测与XPE模拟计算对比分析
- 博图无法链接plc下载程序 设置选择网卡
- 完整elasticsearch安装及其插件安装
- 大容量U盘显示为小容量的解决方法
- 【托业】【跨栏】TEST06
- Oracle TO_DATE 日期格式
- 单纯形法具体步骤记录