存储从底到上的顺序应该是:
远程文件的存储---磁盘---主存----L3高速缓存(这个高速缓存在主板上) (cpu共享)
---L2高速缓存---L1高速缓存---寄存器 (cpu内部)
cpu要读一个数的时候,肯定是从上往下找的,依次是:寄存器--L1--L2--L3 --主存 --硬盘--远程文件存储设备。
这样是有问题的,假如一个数在内存里,这个数会被load到L3的高速缓存里。从L3 - L2的时候,因为L2是cpu内部的,每一个cpu都有L2。
现在考虑这样一个问题,假如要读 x,y两个数,从内存里load到L3里,这都是cpu共享的,但是从L3--L2的时候,每一个cpu都有L2,那么就会load到不同的cpu的内部,假如第一个cpu把x变成1,第二个cpu把x变成2,就会产生数据不一致的问题。当第一个cpu把x改成5的时候,第二个cpu怎么才能知道第一个cpu改了呢?
硬件上解决这个问题的方法是:BusLock。。cpu读L3的时候是通过系统总线的,把这个总线锁住,即:第一个cpu访问L3的时候,第二个cpu不允许访问L3,但是这种直接加锁的方法,效率偏低。。
再发展新的cpu会采用各种各样的缓存一致性协议,inter采用的是MESI协议
M Modified
E Exclusive
S Share
I invaild
cpu每个cache line标记4种状态,用额外的两位
缓存锁的缺陷是:
有些无法被缓存的数据,或者跨越多个缓存行的数据,依然要使用总线锁。
综上所述:
现代cpu的数据一致性实现就是:缓存锁(MESI)+总线锁
除了这些锁和协议以外,还有缓存行对齐的优化。
在硬件层面上,cpu为了提高指令的执行效率,会在一条指令的执行过程中去同时执行另一条指令,但是前提是这两条指令没有依赖关系。那么没有依赖关系的话,就可以乱序执行。
读过程无所谓,写也可以进行合并。
就是加内存屏障,注意是cpu级别的内存屏障,不是JVM的。
在intel的cpu的内存屏障,屏障两侧的指令不可重排
有sfence( s是store两个写之间加内存屏障,两个写之间不可乱序)
lfence( L是load两个读之间加内存屏障,两个读之间不可乱序)
mfence(两个读写之间加内存屏障,两个读写之间不可乱序)
但是在java中,volatile有序性的保证有可能是用lock汇编指令实现的。
JVM里的有序性并不一定依赖于 硬件级别的内存屏障还可依赖于 硬件级别的lock指令
网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。
添加我为好友,拉您入交流群!
请使用微信扫一扫!