对于伪共享的错误理解
Posted cold-windy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对于伪共享的错误理解相关的知识,希望对你有一定的参考价值。
昨天学到了伪共享,基本理解了大致的意思:
1,数据变量存储的基本单位是缓存行,有计算机操作系统基础的都知道,现代的计算机为了解决cpu和主存之间的速度差异(主要是cpu比主存的与运行速度快太多了),提出了cache的概念,也就是缓存,一般会有多级缓存,这个不多说。但是现在的这些缓存行的大小一般都是蛮大的,比如说有64个字节,所以一个缓存行就可以存储多个变量,比如说一个long类型的变量是8个字节,所以一行可以扔8个long。
2.那么现在cpu读取数据就是要读取这个数据在的缓存行,而且现在问题来了,由于什么MESI协议(cv过来的),
MESI协议
多核CPU都有自己的专有缓存(一般为L1,L2),以及同一个CPU插槽之间的核共享的缓存(一般为L3)。不同核心的CPU缓存中难免会加载同样的数据,那么如何保证数据的一致性呢,就是MESI协议了。
在MESI协议中,每个Cache line有4个状态,可用2个bit表示,它们分别是:
M(Modified):这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中;
E(Exclusive):这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中;
S(Shared):这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中;
I(Invalid):这行数据无效。
那么,假设有一个变量i=3(应该是包括变量i的缓存块,块大小为缓存行大小);已经加载到多核(a,b,c)的缓存中,此时该缓存行的状态为S;此时其中的一个核a改变了变量i的值,那么在核a中的当前缓存行的状态将变为M,b,c核中的当前缓存行状态将变为I
在多核计算机中,也就是现在有多个cpu,一个cpu读取了变量a所在的缓存行以后,对于这个缓存行它就失效了,所以导致一个关键的问题。
3.是什么问题呢?就是一个缓存行中可能不止有个a还有一个b,在a的旁边,那么假如现在cpu1读取了变量a,那么变量b也就不能在用了,所以对于现在有个cpu2想用这个b,那么它就不能用缓存里的,只能到主存中去拿,那么肯定会变慢啊(不然为什么加缓存)。感觉这里特别像被volatile修饰了一样。
4.对于这个问题解决方法我就不多说了。我说一下,我脑子不好的问题,思想出了问题,我在想的是既然已经加了volatile修饰,那么肯定会到主存中拿数据啊,为什么会变慢呢?良久以后,我发现了问题所在,volatile修饰的只是a,那么对于cpu2来说,他只是想要一个b,跟a又有什么关系呢?他可以从cache中拿啊,而且对于没有被volatile修饰的变量来说,你即使发生了伪共享,但是不会触及到主存那一块中,因为没有被volatile修饰以后,它就不会每次修改以后都更新主存中的值他只是一个普通的变量,存在可见性的问题,那么即使别的内核需要更新缓存行,也就不会有正确的结果,相应的速度也就比有修饰volatile的快了,因为jvm会将这些值存储在线程栈中,不会及时回写给主内存, 各个线程之间也就不会互相干扰。
5.我不知道我这么想对不对,但是这是我看了蛮多博客以后的结论了,如果你觉得有问题,或者有疑义,可以评论告诉我。
以上是关于对于伪共享的错误理解的主要内容,如果未能解决你的问题,请参考以下文章
伪共享和缓存行填充,从Java 6, Java 7 到Java 8
从缓存行出发理解volatile变量伪共享False sharingdisruptor