java程序员使用高级语言,大多时间不必要关心CPU层面的东西,但是却有必要掌握特点的CPU知识点,今天就为大家整理一下我们需要关心哪些CPU层面的知识。
上图为计算机中CPU与内存之间基本组成图,其中
PC,program counter,存放指令地址;
Registers为指令寄存器,存放指令中的数据;
ALU为运算单元;
而指令则存储在内存中,即图中红色区域。
那么内存中的指令是什么,又改怎么样被CPU计算呢?
举个例子:3+5 这个指令。
首先操作系统会把这条指令通过二进制编码的方式存储于内存。CPU通过总线加载内存中所有指令,把地址存储在PC里。指令中的相关数据,3,5,+则被存放到registers中。
然后ALU运算单元加载registers中的指令数据,计算出结果为8。再通过总线写到内存中。这样就完成了一条指令的执行。
那么图中黄色区域cache的作用又是什么呢?
这里的cache可以分为L1,L2,L3.
我们来看下面这幅图:
这幅图展示的是计算机中各个硬件的运算速度,越往塔尖则速度越快。其中ALU 运算单元模块就是塔尖部分。
在计算机的世界里,ALU的速度比主存要快很多倍,为了提高运算效率CPU引入cache缓存概念,按照离ALU的远近分为L1,L2,L3,离的越近速度越快,其中L3为一个CPU内多个核共享,如下图:
这样就会产生一个问题,CPU会乱序执行。
这是CPU提高执行效率的举措,如下图展示:
这是中学课文里学过的统筹方法问题,顺序执行则执行的时间会稍长,而乱序执行则会缩短执行时间。
而造成这种乱序执行的方法就是cache缓存,当一条指令在靠近CPU的cache上时肯定是比从内存新加载的指令先执行,如下图:
如上图,x和y指令被加载到cpu缓存中,那么下次执行时肯定从cpu缓存中取指令执行。加入这是主内容又产生了z指令,即便z指令早于x和y指令调度cpu的,那么也是x和y指令先执行。
这样一来又有一个问题:上图中假如左边的cpu修改了x,右边cpu修改y,那么这时候如何保障左右两核cpu执行的结果一致呢?即缓存一致性问题
这就是java中volatile关键字出现的原因,volatile关键字的作用:1、禁止指令重排序;2、保证内从可见性。
怎么实现的呢?
使用缓存一致性协议,不同的CPU厂家使用协议不一样,intel使用的是MESI ,实现步骤如下:
MESI标记cpu的每个cache line有四种状态:Modified,Exclusive,Shared,Invalid。
1、左核cpu修改了x指令时,将状态标记为Modified。
2、右核cpu的x指令就会变成无效,即Exclusive。
3、左核cpu会把修改后的x指令反写到主内存,此时状态为Shared。
4、右核cpu会从主内从中load最新的x数据,状态标记为Invalid。这是才可以正常执行。
那么左右两核cpu时怎么知道x的状态变化的呢,原因就是使用缓存锁,如果有些无法被缓存的数据或者跨越多个缓存行的数据,则必须使用总线锁做为托底。如下图: