CPU缓存一致性MESI以及伪共享分析
CPU的缓存一致性MESI
缓存一致性协议有很多不止MESI,主要是因为inter使用的是MESI,而大多数人使用的是inter。
什么是MESI?
MESI 是指4中状态的首字母。每个Cache line有4个状态,可用2个bit表示
M:修改,就是此时CPU从主存中拿到的值已经被该CPU修改过了
E:独享,此时CPU从主存中拿到的值只在该CPU中
S:共享,此时CPU拿到的值和主存中一致,且存在于多个CPU缓存中
I:无效,此时CPU拿到的数据和主存中不一致,被其他CPU更改过了
虽然硬件层次上使用了缓存一致性协议,但是有些数据过大或者不能放到缓存中也是一样要进行锁总线,来实现一致性。
缓存数据的时候会把这个数值所在行都放到缓存中,这样做的原因是因为访问此值的相邻值的概率特别大,防止反复缓存。
缓存行的话就会出现一个问题就是效率低
原因:当CPU1访问缓存中的X值,CPU2访问缓存中的Y值,此时正好X,Y两个值在同一个缓存行上面,那么当CPU1对X值进行了修改那么就要同步到内存中,CPU2发现缓存行被更改了就要重新同步一份新的,这样CPU1和CPU2完全是没有关系的两个操作确导致了频繁更新缓存行,这样会导致效率变低。
这种情况也被称之为:伪共享
解决办法:让值不在同一个缓存行内,比较经典的一个使用方式如下:这种方式叫缓存行对齐
disruptor框架用的就是这种
ps:JVM 要求Java的对象占用的内存大小必须是8bit的整数倍,所以后面有几个字节用于把对象的大小补齐值8bit 倍数。这样a不管是和前7bit组成8bit还是和后7bit组成8bit都是只有自己
还有一种方式是java8之后提供的一个注解@Contended,可以将被注解的变量不和任何变量在同一缓存行中,但是如果只是用这个注解是没有效果的,还需要在jvm启动时设置-XX:-RestrictContended即可。
ps: