将变量推入堆栈和生活在Stack中的变量区别?

所以我知道存在两个内存区域: StackHeap

我也知道如果你创建一个局部变量,它将存在于栈中,而不是堆中。 随着我们向其中推送数据,堆栈将会增长,如下所示:

在这里输入图像描述

现在我会试着去消除我对你的困惑:

例如这个简单的Java代码:

public class TestClass {
    public static void main(String[] args)  {
        Object foo = null;
        Object bar = null;
    }
}

被翻译成这个字节码:

public static void main(java.lang.String[]);
  Code:
   Stack=1, Locals=3, Args_size=1
   0:   aconst_null
   1:   astore_1
   2:   aconst_null
   3:   astore_2
   4:   return

LineNumberTable: 
line 5: 0
line 6: 2
line 7: 4

LocalVariableTable: 
Start  Length  Slot  Name   Signature
0      5      0    args       [Ljava/lang/String;
2      3      1    foo       Ljava/lang/Object;
4      1      2    bar       Ljava/lang/Object;

根据定义, acons_null是:

push a null reference onto the stack

astore_1是:

store a reference into local variable 1

我遇到的困惑是,我们将foo推入堆栈,然后我们再次将它存储在堆栈中? 在一个局部变量中存储一个引用是什么意思? 该地区变量在哪里居住? 我们将foo推入的是同一个堆栈还是这些独立的堆栈?

现在,如果我在第一个对象上调用了一个方法,我将它们推入堆栈,因为堆栈指针指向我推入的最后一个元素,它将如何处理?


JVM中每个线程都有一个堆栈。 每个堆栈由多个框架组成:每个方法调用创建一个新框架,并且当方法调用完成时,框架被销毁。

在一个堆栈框架内有两个区域:

  • 操作数堆栈 (请勿将此处的单词“堆栈”与JVM堆栈本身混淆 - 这里的堆栈将该区域表示为后进先出结构)。
  • 一组局部变量 ,其中每个变量都有一个索引(从零开始)。
  • 根据JVM的实现,它们可能在内存中连续或不连续。 从逻辑上讲,它们是堆栈框架的两个独立部分。

    正如在aconst_null的描述中所解释的aconst_nullaconst_null指令将null对象引用推入操作数堆栈

    正如astore_<n> (其中n可能为0,1,2或3)的说明中所解释的:

    <n>必须是当前帧的本地变量数组的索引(§2.6)。 操作数堆栈顶部的objectref必须是returnAddress类型或reference类型。 它从操作数栈中弹出,并且<n>处局部变量的值被设置为objectref

    因此,在您的示例中,语句Object foo = null将转换为以下内容:

  • null (一个指向“nothing”的特殊引用)推到操作数堆栈的顶部。
  •   operand stack
       __________
      |   null   | <-- null is pushed on the operand stack
      |__________|
      |          |
      |__________|
      |          |
      |__________|
    
  • 从操作数堆栈中弹出引用并将其存储在索引为1的局部变量中。此局部变量对应于foo
  •   operand stack                           local variables
       __________      _______________ _______________ _______________ _______________
      |          |    |      args     |   foo (null)  |               |               |
      |__________|    |_______0_______|_______1_______|_______2_______|_______3_______|
      |          |                    store null in LV#1 
      |__________|
      |          |
      |__________|
    

    除了null存储在索引为2的局部变量中之外,对于Object bar = null相同的步骤。

    来源:Java虚拟机规范(请参阅本节)。


    你应该看看Java堆栈结构。

    一个java堆栈框架包含3件事情:

  • 局部变量表
  • 操作数堆栈
  • 对类的常量池AKA帧数据的引用
  • 因此, push a null reference onto the stack - >将引用推入操作数堆栈。

    store a reference into local variable 1 - >将参考存储在局部变量表的插槽1中


    您可以将操作数堆栈看作临时变量。 每个方法调用都是本地的,它的大小可以在编译时确定。

    如果你想对任何类型的变量(局部变量,静态变量或非静态变量)做任何事情,你可以通过操作数堆栈来完成。 Java字节码指令主要仅与操作数堆栈一起工作。

    例如,

  • foo = bar将对应于aload_2astore_1 ,它仅仅意味着将局部变量2的值压入操作数堆栈并将操作数堆栈顶部的任何内容弹出到局部变量1
  • if (foo == null) ...对应于aload_1ifnonnull 5 ,后者告诉JVM:如果操作数堆栈顶部的内容不为空,则跳转到下一个5指令偏移量; 否则,继续下一条指令。
  • int x = args.length将对应于aload_0arraylengthistore_3 ,这意味着推送局部变量0,在操作数堆栈顶部弹出数组并将其长度推回,弹出整数并将其存储在局部变量3中
  • 数字运算如iaddisubimulidiv从操作数堆栈中弹出两个整数值并将结果返回
  • 当调用一个方法时,操作数堆栈被弹出并作为参数传递给新方法的局部变量。
  • putstatic / getstatic弹出/推动/从静态变量
  • putfield / getfield弹出/推送/从非静态变量
  • 链接地址: http://www.djcxy.com/p/82743.html

    上一篇: Pushing variables to Stack and Variables living in the Stack difference?

    下一篇: Stack Frames, Method Invocation and garbage Collection