将变量推入堆栈和生活在Stack中的变量区别?
所以我知道存在两个内存区域: Stack和Heap 。
我也知道如果你创建一个局部变量,它将存在于栈中,而不是堆中。 随着我们向其中推送数据,堆栈将会增长,如下所示:
现在我会试着去消除我对你的困惑:
例如这个简单的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的实现,它们可能在内存中连续或不连续。 从逻辑上讲,它们是堆栈框架的两个独立部分。
正如在aconst_null
的描述中所解释的aconst_null
, aconst_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
|__________|
| |
|__________|
| |
|__________|
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件事情:
因此, push a null reference onto the stack
- >将引用推入操作数堆栈。
store a reference into local variable 1
- >将参考存储在局部变量表的插槽1中
您可以将操作数堆栈看作临时变量。 每个方法调用都是本地的,它的大小可以在编译时确定。
如果你想对任何类型的变量(局部变量,静态变量或非静态变量)做任何事情,你可以通过操作数堆栈来完成。 Java字节码指令主要仅与操作数堆栈一起工作。
例如,
foo = bar
将对应于aload_2
和astore_1
,它仅仅意味着将局部变量2的值压入操作数堆栈并将操作数堆栈顶部的任何内容弹出到局部变量1 if (foo == null) ...
对应于aload_1
和ifnonnull 5
,后者告诉JVM:如果操作数堆栈顶部的内容不为空,则跳转到下一个5指令偏移量; 否则,继续下一条指令。 int x = args.length
将对应于aload_0
, arraylength
, istore_3
,这意味着推送局部变量0,在操作数堆栈顶部弹出数组并将其长度推回,弹出整数并将其存储在局部变量3中 iadd
, isub
, imul
, idiv
从操作数堆栈中弹出两个整数值并将结果返回 putstatic
/ getstatic
弹出/推动/从静态变量 putfield
/ getfield
弹出/推送/从非静态变量 上一篇: Pushing variables to Stack and Variables living in the Stack difference?