简体   繁体   English

JVM如何知道方法堆栈中变量的位置?

[英]How JVM know the location a variable in stack of a method?

This question may be a silly one or may be a duplicate. 这个问题可能是愚蠢的,也可能是重复的。 I am confused with how the variables are retrieved from stack when program is referring to that variable. 当程序引用该变量时,我对如何从堆栈中检索变量感到困惑。 An object is stored in heap and the location is stored in the reference variable and the reference variable containing the heap address itself is stored in stack. 对象存储在堆中,位置存储在引用变量中,包含堆地址本身的引用变量存储在堆栈中。 But how JVM figure out that reference variable is stored in what location in stack. 但JVM如何确定该引用变量存储在堆栈中的哪个位置。

Lets consider the example just to make clear what I am confused about. 让我们考虑这个例子只是为了弄清楚我对此感到困惑。

Class Test {
    public void test() {
        Object a = new Bar();
        Object b = new Foo();
        System.out.println(a);
    }
}

Lets say method test() is getting executed. 让我们说方法test()正在执行。 So stack will be allocated for test(). 因此堆栈将被分配给test()。

Now when the line ' Object a = new Bar(); 现在当' Object a = new Bar(); ' is executed , Bar object will be created in Heap and the actual variable 'a' , whose value is the address location of the Bar object , will be stored in stack of test(). '执行,Bar对象将在Heap中创建,实际变量'a' (其值为Bar对象的地址位置)将存储在test()的堆栈中。

Again on the line ' Object b = new Foo(); 再次在' 对象b =新Foo(); ' same thing happens. “同样的事情发生了。 Foo object will be created in Heap and the actual variable 'b' ,whose value is the address location of the Foo object, will be stored in stack of test(). Foo对象将在Heap中创建,实际变量'b' (其值为Foo对象的地址位置)将存储在test()的堆栈中。

Now when he line ' System.out.println(a); 现在当他排队' System.out.println(a); ' is executed , how does JVM know from which location in the stack , the value of 'a' should be retrieved. '执行了,JVM如何知道堆栈中的哪个位置,应该检索'a'的值。 Means what links the variable 'a' and its location in the stack ? 意味着什么链接变量'a'及其在堆栈中的位置?

You're almost there, there's just one missing link in your understanding. 你几乎就在那里,你的理解中只有一个缺失的环节。

Local variables (or the references to the object stored in a local variable, if we're talking about non-primitive types) are actually stored in a local variable table , not on the operand stack. 局部变量(或者存储在局部变量中的对象的引用,如果我们讨论的是非基本类型)实际上存储在局部变量表中 ,而不是存储在操作数堆栈中。 They're only pushed onto the stack when they are to be used by a call. 当它们被呼叫使用时,它们只被推入堆栈。

(What is confusing is that the local variable table itself is also stored on a stack, but that's a separate stack from what the bytecode uses for operands. From the bytecode's perspective it is a real table, with fixed size and freely indexable.) (令人困惑的是局部变量表本身也存储在堆栈中,但这是与字节码用于操作数的单独堆栈。从字节码的角度来看,它是一个真实的表,具有固定的大小并且可以自由索引。)

You can use javap to look at what bytecode is generated from your code. 您可以使用javap查看代码生成的字节码。 What you'll see is something like this: 你会看到的是这样的:

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
}

First of all, what is this line? 首先,这条线是什么?

  stack=3, locals=3, args_size=1

It is metadata that tells the JVM that this method has an operand stack no deeper than 3 entries, 3 local variables and takes 1 argument. 元数据告诉JVM该方法的操作数堆栈不超过3个条目,3个局部变量并且取1个参数。 But surely that isn't right, our method takes no argument and clearly only has 2 local variables! 但肯定是不对的,我们的方法不需要参数,显然只有2个局部变量!

The answer to this is that non-static methods always have a "0th argument": this . 答案是非静态方法总是有一个“第0个参数”: this This explains the argument count, and leads us to the next important discovery: arguments of a method are stored in the local variable table too . 这解释了参数计数,并引导我们进行下一个重要的发现: 方法的参数也存储在局部变量表中 So our table will have entries 0,1,2, with 0 containing this at the start and 1 and 2 uninitialised. 所以我们的表将有条目0,1,2,其中0在开始时包含this ,1和2未初始化。

With that out of the way, let's look at the code! 有了这个,让我们看看代码吧! First up it's lines 0-7 : 首先是0-7行:

  1. The new opcode creates a new instance of Bar and stores the reference on the stack. new操作码创建一个新的Bar实例并将引用存储在堆栈中。
  2. dup creates a copy of the same reference on the top of the stack (so you've got two copies now sitting there) dup在堆栈顶部创建相同引用的副本(所以你现在有两个副本)
  3. invokespecial #3 calls the constructor of Bar and consumes the top of the stack. invokespecial #3调用Bar的构造函数并使用堆栈的顶部。 (now we've only got one copy left) (现在我们只剩下一份)
  4. astore_1 stores the remaining reference in local variable number number 1 ( 0 is for this in this case) astore_1存储在局部变量号码数其余参考10是用于this在这种情况下)

This is what Object a = new Bar(); 这就是Object a = new Bar(); has been compiled into. 已被编译成。 Then you get the same for Object b = new Foo(); 然后你得到相同的Object b = new Foo(); (lines 8-15 ). (第8-15行)。

And then comes the interesting bit, from line 16 : 从第16行开始,有趣的是:

  1. getstatic #6 pushes the value of System.out on the stack getstatic #6System.out的值压入堆栈
  2. aload_1 pushes local variable number 1 ( a ) on the stack too aload_1在堆栈上推送局部变量编号1( a
  3. invokevirtual #7 consumes both entries, calling println() on System.out with a as its input parameter. invokevirtual #7两个条目,在System.out上调用println() ,并输入a作为输入参数。

If you want to delve into it deeper, or you just want to point out my mistakes, the official reference for all of the above is here . 如果你想深入研究它,或者你只是想指出我的错误,那么上述所有内容的官方参考就在这里

THe JVM stores Stack Frames and these hold arrays for the variables. JVM存储堆栈帧,这些存储变量的数组。

Each frame (§2.6) contains an array of variables known as its local variables.
[...]
Local variables are addressed by indexing.

Found Here 这里找到

JVM is not a onefold data structure, actually it has several different mechanisms. JVM不是一个单一的数据结构,实际上它有几种不同的机制。 When a program is executed, JVM organizes all memories it needs and allocate them into several different memory stacks called runtime data areas . 执行程序时,JVM会组织所需的所有内存,并将它们分配到几个称为运行时数据区的不同内存堆栈中。

Here is a more detailed explanation: Architecture of JVM 这是一个更详细的解释: JVM的体系结构

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM