当前位置:网站首页>缓存--伪共享问题
缓存--伪共享问题
2022-08-03 11:10:00 【zpv2jdfc】
接上一篇 CPU缓存一致性问题
什么是伪共享
伪共享问题指两个线程A和B,他们俩写入同一个cache block的不同变量时,会导致另一个cpu核心的缓存失效的问题。我们来详细看一下伪共享问题到底是怎么产生的:
假设A线程要访问变量A,B线程要访问变量B,并且变量A和B会被分配到同一个cache line中:
接下来,A线程要读取变量A。此时A、B所在的cache line被加载到核心1的cache中,并且状态被标记为独占:
此时,B线程要访问变量B,那么这个cache line被加载到核心2的cache中。并且两个核心的cache line都标记为共享:
接下来,问题来了。假设A线程修改了变量A,为了保证数据一致性,就需要把核心2的cache line标记为失效:
这样一来,如果B要读取变量B的值,就需要A先将cache line写回内存,然后B再从内存中读取。也就是说,明明B变量自始至终都没有改变过,但是在访问时却需要重新从内存读取。如果A、B两个线程轮流修改变量A、B的话,伪共享问题会严重影响性能。
解决伪共享的办法
1.字节填充
对上面这种情况,如果A、B不被分配在同一个cache line中自然就不存在伪共享问题了。
如何让A、B分配在不同cache line中呢?我们可以通过这个命令查看cache line的大小
more /sys/devices/system/cpu/cpu1/cache/index0/coherency_line_size
可以看到cache line大小为64字节。接下来,我们来对比一下使用字节填充后程序性能会提高多少。
不使用字节填充:
public class Main {
public static void main(String[] args) throws InterruptedException {
Pair pair=new Pair();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 0x7fff_ffff; i++) {
pair.x++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 0x7fff_ffff; i++) {
pair.y++;
}
});
long start = System.currentTimeMillis();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(System.currentTimeMillis() - start);
}
}
class Pair{
// long x1,x2,x3,x4,x5,x6,x7;
volatile long x=0;
// long y1,y2,y3,y4,y5,y6,y7;
volatile long y=0;
}
63615
使用字节填充:
public class Main {
public static void main(String[] args) throws InterruptedException {
Pair pair=new Pair();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 0x7fff_ffff; i++) {
pair.x++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 0x7fff_ffff; i++) {
pair.y++;
}
});
long start = System.currentTimeMillis();
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(System.currentTimeMillis() - start);
}
}
class Pair{
long x1,x2,x3,x4,x5,x6,x7;
volatile long x=0;
long y1,y2,y3,y4,y5,y6,y7;
volatile long y=0;
}
10781
注意这里要用volatile关键字防止编译器优化指令。
2.使用@Contented 注解
@Contented注解原理也是字节填充,注解既可以加在字段,也可以加在类上。加在字段上表示这个字段单独占一个缓存行,加在类上表示类中所有字段都独占一个缓存行。
使用@Contented注解需要配置jvm参数 -XX:-RestrictContended
,通过 -XX:ContendedPaddingWidth
可以修改填充的字节大小,有效值范围0 - 8192,默认是128字节。
边栏推荐
猜你喜欢
Lease recovery system based on PHP7.2+MySQL5.7
[LeetCode—Question 2 Sum of Two Numbers Detailed Code Explanation ] The source code is attached, which can be copied directly
嵌入式软件组件经典架构与存储器分类
Generate interface documentation online
如何检索IDC研究报告?
记住用户名案例(js)
完全背包问题
For invoice processing DocuWare, cast off the yoke of the paper and data input, automatic processing all the invoice received
Win10/11 删除文件资源管理器左侧栏目文件夹
多态详细讲解(简单实现买票系统模拟,覆盖/重定义,多态原理,虚表)
随机推荐
What is the ERC20 token standard?
零拷贝、MMAP、堆外内存,傻傻搞不明白...
Basic using MySQL database
Generate interface documentation online
shell编程-测试
[Explanation of JDBC and inner classes]
干货!一种被称为Deformable Butterfly(DeBut)的高度结构化且稀疏的线性变换
Programmers architecture practice way: software architecture basic concepts and thinking
LeetCode 899 Ordered queue [lexicographical order] HERODING's LeetCode road
XDR平台架构与关键技术解析
BPMN和DMN基本概念和使用案例
Matplotlib
科普大佬说 | 黑客帝国与6G有什么关系?
ETL data cleaning case in MapReduce
程序员架构修炼之道:如何设计出可持续演进的系统架构?
3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析
Fastjson反序列化
Classical Architecture and Memory Classification of Embedded Software Components
Question G: Word Analysis ← Questions for the second provincial competition of the 11th Blue Bridge Cup Competition
Babbitt | Metaverse daily must-read: Players leave, platforms are shut down, and the digital collection market is gradually cooling down. Where is the future of the industry?...