JVM架构 |栈式指令集与寄存器指令集有什么区别?
文章目录
- 一、两种指令集的区别
- 二、代码直观演示两种指令集架构
- 三、基于栈的解释器执行过程
- 四、总结
一、两种指令集的区别
指令集的架构模型分为基于栈的指令集架构
与基于寄存器的指令集架构
两种,HotSpot虚拟机中的任何操作都需要入栈和出栈的步骤,即使用栈来管理运行,而HotSpot本身就是基于栈的指令集架构
;
基于寄存器架构的指令集典型应用是传统PC上x86的二进制指令集、Android的Davlik虚拟机(Google在Android上就选择了此种方案)。
下图展示了两种指令集架构的区别:
二、代码直观演示两种指令集架构
下面举个例子,分别使用这两种指令集计算2+3的结果
在IDEA中对2+3操作进行javap -v反编译
,得到了8行指令集。这里只需要要和基于寄存器得出的指令集做一个直观的对比即可,更详细的执行栈式执行过程可以参照下文给出的另一个例子。
而使用寄存器架构对2+3操作的指令集只有下面两行
三、基于栈的解释器执行过程
下面通过一段Java代码,演示虚拟机中的字节码是如何执行的
stack=2,locals=4可以看到Javap提示这段代码需要深度为2的操作数栈和4个变量操的局部变量空间。
bipush指令的作用是将单字节的整形常量值(-128~127)推入操作数栈顶端,跟随有一个参数,指明推送的常量值是多少,这里是100。
istore_1指令的作用是将操作数栈顶的整型值出栈并存放到第1个局部变量槽中。 后续4条指令(直到偏移为11的指令为止) 都是做一样的事情, 也就是在对应代码中把变量
a、 b、 c赋值为100、 200、 300。 这4条指令的图示略过。
iload_1指令的作用是将局部变量表第1个变量槽中的整型值复制到操作数栈顶端。
iload_2指令的执行过程与iload_1类似, 把第2个变量槽的整型值入栈。
iadd指令的作用是将操作数栈中头两个栈顶元素出栈, 做整型加法,然后把结果重新入栈。 在iadd指令执行完毕后, 栈中原有的100和200被出栈,它们的和300被重新入栈。
iload_3指令把存放在第3个局部变量槽中的300入栈到操作数栈中。 这时操作数栈为两个整数300。 下一条指令imul是将操作数栈中头两个栈顶元素出栈, 做整型乘法, 然后
把结果重新入栈, 与iadd完全类似, 故省略图示。
ireturn指令是方法返回指令之一, 它将结束方法执行并将操作数栈顶的整型值返回给该方法的调用者。 到此为止, 这段方法执行结束。
四、总结
由于跨平台性的设计,Java的指令都是根据栈式指令集架构来设计的。不同平台CPU架构不同,所以不能设计为寄存器架构的。栈式架构的优点是跨平台,指令集小,编译器容器实现;缺点是性能下降,实现相同的功能需要更多的指令。
面试题
:时至今日,HotSpot虚拟机的宿主环境已经不局限于嵌入式平台了,那么为什么不将架构更换为性能更好的寄存器指令集架构呢?
两种指令集架构各有优劣,并存发展。首先,在设计和实现上,基于栈式的架构更简单。其次无论平台的资源是否受限制,基于栈式的架构都是可以使用的。(针对栈式的优点,可以继续balabala…)