一、两种指令集的区别

指令集的架构模型分为基于栈的指令集架构基于寄存器的指令集架构两种,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…)

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐