Java 什么是操作数堆栈?

Java 什么是操作数堆栈?,java,jvm,Java,Jvm,我正在阅读有关JVM体系结构的文章。今天我读了关于操作数堆栈的概念。根据一篇文章: 操作数堆栈在字节码指令执行期间使用 与通用寄存器在本机CPU中的使用方式类似 我不明白:操作数堆栈到底是什么,它在jvm中是如何工作的?操作数堆栈保存着运算符执行操作时使用的操作数。操作数堆栈上的每个条目都可以保存任何Java虚拟机类型的值 从 Java虚拟机指令从操作数中获取操作数 堆栈,对其进行操作,并将结果推回操作数 堆栈操作数堆栈还用于准备要执行的参数 传递给方法并接收方法结果 例如,指令将添加两个整数值

我正在阅读有关JVM体系结构的文章。今天我读了关于操作数堆栈的概念。根据一篇文章:

操作数堆栈在字节码指令执行期间使用 与通用寄存器在本机CPU中的使用方式类似


我不明白:操作数堆栈到底是什么,它在jvm中是如何工作的?

操作数堆栈保存着运算符执行操作时使用的操作数。操作数堆栈上的每个条目都可以保存任何Java虚拟机类型的值

Java虚拟机指令从操作数中获取操作数 堆栈,对其进行操作,并将结果推回操作数 堆栈操作数堆栈还用于准备要执行的参数 传递给方法并接收方法结果

例如,指令将添加两个整数值,所以它将从操作数堆栈中弹出最上面的两个整数值,并在添加后将结果推入操作数堆栈

有关更详细的参考资料,您可以查看

在操作数堆栈的上下文中对其进行汇总

    _______________________________
   |        _____________________  |
   |       |         + --------+ | |
   |  JVM  |         | Operand | | | 
   | Stack |  FRAME  |  Stack  | | |
   |       |         +---------+ | |
   |       |_____________________| |
   |_______________________________|
  • JVM支持多线程执行环境。每根线 执行在创建线程的同时创建其私有java虚拟机堆栈(JVM堆栈)
  • 这个Java虚拟机堆栈存储帧。框架保存数据、部分结果、方法返回值并执行动态链接
  • 每个帧包含堆栈,称为操作数堆栈,它保存JVM类型的操作数值。操作数堆栈的深度在编译时确定,并用运算符更新

这是各种字节码操作如何获得输入以及如何提供输出的问题

例如,考虑<代码> IADAD操作,将两个<代码> int <代码> s添加在一起。要使用它,请在堆栈上推送两个值,然后使用它:

iload_0     # Push the value from local variable 0 onto the stack
iload_1     # Push the value from local variable 1 onto the stack
iadd        # Pops those off the stack, adds them, and pushes the result
现在堆栈上的最大值是这两个局部变量的和。下一个操作可能会获取顶层堆栈值并将其存储在某个位置,或者我们可能会在堆栈上推送另一个值以执行其他操作

假设要将三个值相加。堆栈使这变得简单:

iload_0     # Push the value from local variable 0 onto the stack
iload_1     # Push the value from local variable 1 onto the stack
iadd        # Pops those off the stack, adds them, and pushes the result
iload_2     # Push the value from local variable 2 onto the stack
iadd        # Pops those off the stack, adds them, and pushes the result
现在,堆栈上的顶部值是将这三个局部变量相加的结果

让我们更详细地看一下第二个示例:

我们假设:

  • 堆栈一开始是空的(这几乎从来都不是真的,但在开始之前我们不在乎上面有什么)
  • 局部变量0包含
    27
  • 局部变量1包含
    10
  • 局部变量2包含
    5
因此,最初:

+−−−−−−−+ | stack | +−−−−−−−+ +−−−−−−−+ 现在我们有了

+−−−−−−−+ | stack | +−−−−−−−+ | 27 | +−−−−−−−+ 它将
10
27
从堆栈中“弹出”,将它们相加,并推送结果(
37
)。现在我们有:

+−−−−−−−+ | stack | +−−−−−−−+ | 37 | +−−−−−−−+ 这给了我们:

+−−−−−−−+ | stack | +−−−−−−−+ | 42 | +−−−−−−−+ +−−−−−−−+ |堆叠| +−−−−−−−+ | 42 | +−−−−−−−+ (当然,这是最重要的。)

但我们不能确切地理解它是什么,以及它在jvm中是如何工作的

JVM定义了虚拟计算机,该计算机的指令集是基于堆栈的。这意味着JVM指令集中的指令通常会从堆栈中推送和弹出操作数。那么比如说,

  • load指令可以从局部变量、实例变量或类变量中获取值,并将其推送到操作数堆栈上
  • 算术指令将从操作数堆栈弹出值,执行计算并将结果推回堆栈,然后
  • 存储指令将从堆栈中弹出一个值并存储它
@T.J.Crowder的回答给出了一个更为具体的例子

操作数堆栈的实现方式是特定于平台的,它取决于代码是被解释的还是被JIT编译的

  • 在解释的情况下,操作数堆栈可能是由解释程序代码管理的数组。push和pop微操作的实现方式如下:

        stack[top++] = value;
    

  • 当代码被JIT编译时,字节码指令序列被转换成本机指令序列,实现与字节码相同的功能。操作数堆栈位置映射到本机寄存器或内存位置;e、 g.在当前本机堆栈帧中。映射涉及各种优化,旨在优先使用寄存器(快)而不是内存(慢)

    因此,在JIT编译的情况下,操作数堆栈不再具有明确的物理存在性,但编译程序的整体行为与操作数堆栈确实存在的情况相同1



1-实际上,考虑Java内存模型时,它可能并不完全相同。然而,记忆模型明确了差异的界限。在单线程计算不与外部交互的情况下(如I/O、时钟等),不可能有明显的差异。

+1供《搭便车者宇宙指南》参考。你让我很开心哈哈哈我可以问一下CPU级操作数堆栈是如何工作的吗?我搞不清他们之间的关系。感觉只有一个或另一个应该做这项工作(即:执行指令):)。如果可能的话,你能简单地解释一下中间的流程吗?@stdout-Java虚拟机与CPU非常相似,这是有意的。一旦HotSpot对字节码进行了最小的首次通过优化,上面的堆栈很可能就是CPU堆栈(我还没有进入VM优化)。事实上,
iadd
很可能成为CPU的
ADD
ADC
(带进位添加)操作或类似操作。
iadd        # Pops those off the stack, adds them, and pushes the result
+−−−−−−−+ | stack | +−−−−−−−+ | 37 | +−−−−−−−+
iload_2     # Push the value from local variable 2 onto the stack
+−−−−−−−+ | stack | +−−−−−−−+ | 5 | | 37 | +−−−−−−−+
iadd        # Pops those off the stack, adds them, and pushes the result
+−−−−−−−+ | stack | +−−−−−−−+ | 42 | +−−−−−−−+
    stack[top++] = value;
    value = stack[--top];