Java JVM如何知道变量在方法堆栈中的位置?
这个问题可能是愚蠢的,也可能是重复的。当程序引用变量时,我对如何从堆栈中检索变量感到困惑。 对象存储在堆中,位置存储在引用变量中,包含堆地址本身的引用变量存储在堆栈中。但JVM如何确定引用变量存储在堆栈中的哪个位置 让我们考虑一下这个例子,弄清楚我所困惑的是什么。Java JVM如何知道变量在方法堆栈中的位置?,java,stack-memory,Java,Stack Memory,这个问题可能是愚蠢的,也可能是重复的。当程序引用变量时,我对如何从堆栈中检索变量感到困惑。 对象存储在堆中,位置存储在引用变量中,包含堆地址本身的引用变量存储在堆栈中。但JVM如何确定引用变量存储在堆栈中的哪个位置 让我们考虑一下这个例子,弄清楚我所困惑的是什么。 Class Test { public void test() { Object a = new Bar(); Object b = new Foo(); System.out.
Class Test {
public void test() {
Object a = new Bar();
Object b = new Foo();
System.out.println(a);
}
}
假设正在执行方法test()。因此,将为test()分配堆栈
现在,当行'对象a=new Bar()'执行后,Bar对象将在堆中创建,实际变量'a'的值是Bar对象的地址位置,将存储在test()的堆栈中
再次在“Object b=new Foo()行上“同样的事情也会发生。Foo对象将在Heap中创建,实际变量'b'(其值是Foo对象的地址位置)将存储在test()的堆栈中
现在当他把‘System.out.println(a)排成一行时当执行strong>'时,JVM如何知道应从堆栈中的哪个位置检索'a'的值。表示变量“a”与其在堆栈中的位置之间的链接是什么?您几乎就要到了,您的理解中只缺少一个链接 局部变量(或对存储在局部变量中的对象的引用,如果我们谈论的是非基元类型)实际上存储在局部变量表中,而不是在操作数堆栈上。它们只有在被调用使用时才会被推到堆栈上 (令人困惑的是,局部变量表本身也存储在堆栈上,但这是一个与字节码用于操作数的堆栈不同的堆栈。从字节码的角度来看,它是一个实表,具有固定大小和自由索引。) 您可以使用
javap
查看从代码生成的字节码。您将看到如下内容:
public void test();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=3, locals=3, args_size=1
0: new #2 // class Test$Bar
3: dup
4: invokespecial #3 // Method Test$Bar."<init>":()V
7: astore_1
8: new #4 // class Test$Foo
11: dup
12: invokespecial #5 // Method Test$Foo."<init>":()V
15: astore_2
16: getstatic #6 // Field java/lang/System.out:Ljava/io/PrintStream;
19: aload_1
20: invokevirtual #7 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
23: return
}
元数据告诉JVM该方法的操作数堆栈深度不超过3个条目、3个局部变量和1个参数。但这肯定是不对的,我们的方法没有参数,显然只有2个局部变量
答案是非静态方法总是有一个“0参数”:this
。这解释了参数计数,并将我们引向下一个重要发现:方法的参数也存储在局部变量表中。因此,我们的表将有条目0,1,2,其中0在开始处包含this
,1和2未初始化
有了这些,让我们看看代码!首先是行0-7
:
new
操作码创建Bar
的新实例,并将引用存储在堆栈上dup
在堆栈顶部创建同一引用的副本(因此您现在有两个副本)invokespecial#3
调用Bar
的构造函数并占用堆栈顶部。(现在我们只剩下一份了)astore_1
将剩余的引用存储在局部变量编号1
中(0
在这种情况下用于此
)objecta=newbar()代码>已编译为。然后对Object b=new Foo()得到相同的结果代码>(行8-15
)
然后是有趣的一点,从第16行开始:
getstatic#6
将System.out的值推送到堆栈上
aload_1
也将本地变量1(a
)推送到堆栈上
invokevirtual#7
使用这两个条目,在System.out上调用println()
,并将a
作为其输入参数
如果您想深入研究,或者只是想指出我的错误,以上所有内容的官方参考是。JVM存储堆栈帧,这些帧保存变量的数组
Each frame (§2.6) contains an array of variables known as its local variables.
[...]
Local variables are addressed by indexing.
发现JVM不是一个单一的数据结构,实际上它有几种不同的机制。当一个程序被执行时,JVM组织它需要的所有内存,并将它们分配到称为运行时数据区的几个不同内存堆栈中
这里有一个更详细的解释:谢谢您的详细回复。只是澄清一下:astore_x将推送到局部变量表中的位置“x”,而aload_x将把存储在表中位置“x”的项推送到堆栈中。这就是rt?@Dinkan的一般想法,当然,astore_x
也会从堆栈中弹出值。好的。知道了。谢谢
Each frame (§2.6) contains an array of variables known as its local variables.
[...]
Local variables are addressed by indexing.