指令重排
指令执行的5个阶段
几乎所有冯▪诺伊曼型计算机CPU,一条指令的执行都可以分为5个阶段:
1、取指令IF;
2、译码和读存取数(读操作数)ID;
3、执行指令EX;
4、存储器访问(计算结果加载到内存)MEM;
5、结果写回(寄存器)WB;
这其中的每一步都交由不同的硬件处理,
同样的步骤需要等待硬件空闲才能继续运行,也就是:
两条连续执行的指令需要消耗至少6个时钟单位。
A=B+C,需要执行4个指令
Java中的代码:A=B+C,需要执行4个指令:
指令1:加载B到寄存器里的R1中;
指令2:加载C到寄存器里的R2中;
指令3:将R1与R2相加,计算得出R3;
指令4:将R3赋值给A。
指令1和指令2之间没有依赖关系,正常依次执行,
指令3依赖于前两个指令的结果,
需要等待指令1、2全部将计算结果加载到内存(MEM)之后,才能进行执行(EX),
指令4依赖于指令3的结果,也需要错位等待。
图片中的红圈表示因为需要等待造成硬件的空闲,叫做气泡,
这样4条指令的时钟单位长度就不是理想中的8,而是9。
A=B+C; D=E+F;
看一个复杂一点的例子
A=B+C;
D=E+F;
指令1:加载B到寄存器里的R1中;
指令2:加载C到寄存器里的R2中;
指令3:将R1与R2相加,计算得出R3;
指令4:将R3赋值给A。
指令5:加载E到寄存器里的R4中;
指令6:加载F到寄存器里的R5中;
指令7:将R4与R5相加,计算得出R6;
指令8:将R6赋值给D。
这样就需要14个时钟单位,
那么有没有办法消减这些气泡,减小硬件空闲造成的损失,
办法是把指令5、6排到指令2之后,
再把指令6排到指令3之后,消除所有气泡,最大程度地利用计算机硬件,
指令重排
时钟单位长度从14缩减到了12,这就是指令重排的目的。
乱序执行
不过指令重排也带来了乱序执行的问题,如果乱序就会产生数据不一致,
Java如何在特定情况下保证有序执行:jvm-02.有序性保证。
不当之处,请予指正。
参考资料:
大道方圆:Java内存模型与指令重排
技术小叮铛:指令重排的意义
顺其自然~:计算机指令执行过程详解