JVM中操作数堆栈的作用是什么? [英] What is the role of operand stack in JVM?

查看:102
本文介绍了JVM中操作数堆栈的作用是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

JVM运行时数据区为每个正在执行的方法提供单独的堆栈。它包含操作数堆栈和局部变量。每次加载变量时,需要 const 到操作数堆栈,然后 store 到局部变量。为什么不直接操作局部变量表,并进行一些看似重复的工作?

JVM Run-time Data Areas separate stack for each method being executed. It contains operand stack and local variables. Every time you load a variable, you need to const to the operand stack and then store to the local variables. Why not directly operate the local variable table, and have some seemingly repeated work?

推荐答案

具有直接操作数的指令集必须进行编码每个指令中的操作数。相比之下,对于使用操作数堆栈的指令集,操作数是隐式的。

An instruction set with direct operands has to encode the operands in each instruction. In contrast, with an instruction set using an operand stack, the operands are implicit.

在查看小的琐碎运算(如加载a)时,隐式参数的优势并不明显。常量变成变量。此示例将操作码,常量,操作码,变量索引序列与操作码,常量,变量索引进行比较,因此似乎直接寻址更简单,更紧凑。

The advantage of implicit arguments is not obvious when looking at a small trivial operation like loading a constant into a variable. This example is comparing an "opcode, constant, opcode, variable-index" sequence with "opcode, constant, variable index", so it seems like addressing directly is simpler and more compact.

但是让我们看一下 return Math.sqrt(a * a + b * b);

假设变量索引从零开始,字节码如下所示:

Assuming the variable indices start at zero, the bytecode looks like

   0: dload_0
   1: dload_0
   2: dmul
   3: dload_2
   4: dload_2
   5: dmul
   6: dadd
   7: invokestatic  #2                  // Method java/lang/Math.sqrt:(D)D
  10: dreturn
  11 bytes total

对于直接寻址架构,我们需要一些东西像

For a directly addressing architecture, we would need something like

dmul a,a → tmp1
dmul b,b → tmp2
dadd tmp1,tmp2 → tmp1
invokestatic #2 tmp1 → tmp1
dreturn tmp1

虽然此序列由较少的指令组成,但是每条指令都必须对其操作数进行编码。当我们希望能够处理256个局部变量时,每个操作数需要一个字节,因此每个算术指令需要三个字节加操作码,调用需要两个加操作码和方法地址,而返回则需要一个加操作码。因此,对于字节边界处的指令,此序列需要19个字节,大大超过等效的Java字节码,同时被限制为256个局部变量,而该字节码最多支持65536个局部变量。

While this sequence consists of fewer instructions, each instruction has to encode its operands. When we want to be able to address 256 local variables, we need a byte per operand, so each arithmetic instruction needs three bytes plus opcode, the invocation needs two plus opcode and method address, and the return needs one plus opcode. So for instructions at byte boundaries, this sequence needs 19 bytes, significantly more than the equivalent Java bytecode, while being limited to 256 local variables whereas the bytecode supports up to 65536 local variables.

这证明了操作数堆栈概念的另一优点。 Java字节码允许组合不同的优化指令,例如要加载整数常量,有 iconst_n bipush sipush ldc 并将其存储到变量中,有 istore_n istore n 宽的istore n 。当直接变量寻址的指令集应支持各种常数和变量数量,但仍支持紧凑型指令时,每种组合都需要使用不同的指令。同样,它将需要所有算术指令的多个版本。

This demonstrates another strength of the operand stack concept. Java bytecode allows to combine different, optimized instructions, e.g. for loading an integer constant there are iconst_n, bipush, sipush, and ldc and for storing it into a variable there are istore_n, istore n, and wide istore n. An instruction set with direct variable addressing would need distinct instructions for each combination when it is supposed to support a wide range of constants and numbers of variables but still support compact instructions. Likewise, it would need multiple versions of all arithmetic instructions then.

除了使用三个操作数形式,您还可以使用两个操作数形式,其中源变量之一指示目标变量。这样可以使指令更紧凑,但是如果之后仍需要操作数的值,则需要附加的传输指令。操作数堆栈形式仍然更紧凑。

Instead of a three operand form, you could use a two operand form, where one of the source variables also indicates the target variable. This results in more compact instructions but creates the need for additional transfer instructions if the operand’s value is still needed afterwards. The operand stack form still is more compact.

请记住,这仅描述了操作。在执行代码时,不需要执行环境严格遵循此逻辑。因此,除了最简单的解释器之外,所有JVM实现都在执行之前将其转换为其他形式,因此原始存储形式对实际执行性能无关紧要。它仅影响空间需求和加载时间,这两者都受益于更紧凑的表示形式。这尤其适用于通过可能很慢的网络连接传输的代码,这是Java最初设计的用例之一。

Keep in mind that this only describes the operations. An execution environment is not required to strictly follow this logic when executing the code. So besides the simplest interpreters, all JVM implementations convert this into a different form before executing, so the original stored form doesn’t matter for the actual execution performance. It only affects the space requirements and loading time, which both benefit from a more compact representation. This especially applies to code transferred over potentially slow network connections, one of the use cases, Java was originally designed for.

这篇关于JVM中操作数堆栈的作用是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆