简体   繁体   English

堆栈框架中的Java运行时常量池引用变量

[英]Java Runtime constant pool reference variable in stack frame

According to the following link the java stack frame contains local variables, operand stack and the current class constant pool reference. 根据以下链接,java堆栈框架包含局部变量,操作数堆栈和当前类常量池引用。 http://blog.jamesdbloom.com/JVMInternals.html http://blog.jamesdbloom.com/JVMInternals.html

Also From Oracle "Structure of JVM" Section 2.6.3. 也来自Oracle“ JVM的结构”第2.6.3节。 "Dynamic Linking - Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support dynamic linking of the method code." “动态链接-每个帧(第2.6节)都包含对当前方法类型的运行时常量池(第2.5.5节)的引用,以支持方法代码的动态链接。”

I have also read that the object in the heap also has a pointer/reference to the class data. 我还读到堆中的对象也具有指向类数据的指针/引用。 https://www.artima.com/insidejvm/ed2/jvm6.html https://www.artima.com/insidejvm/ed2/jvm6.html

The stack frame will contain the "current class constant pool reference" and also it will have the reference to the object in heap which in turn will also point to the class data. 堆栈框架将包含“当前类常量池引用”,并且还将具有对堆中对象的引用,而该对象又将指向类数据。 Is this not redundant?? 这不是多余的吗?

For example. 例如。

public class Honda {
  public void run() {
    System.out.println("honda is running");
  } 
  public static void main(String[] args) {
  Honda h = new Honda();
  h.run(); //output honda is running
  }
}

When h.run() is going to be executed, jvm will create a new stack frame and push h on the stack frame. 当将要执行h.run()时,jvm将创建一个新的堆栈框架并将h压入该堆栈框架。 h will point to the object in heap which in turn will have a pointer to class data of Honda. h将指向堆中的对象,该对象又将具有指向本田类数据的指针。 The stack frame will also have current class constant reference. 堆栈框架还将具有当前的类常数参考。 Is this correct? 这个对吗? If not please shed some light on this. 如果没有,请对此有所说明。

Is this not redundant?? 这不是多余的吗?

Maybe it is redundant for instance methods and constructors. 也许对于实例方法和构造函数是多余的。

It isn't redundant for static methods or class initialization pseudo-methods. 对于静态方法或类初始化伪方法来说,这不是多余的。


It is also possible that the (supposedly) redundant reference gets optimized away by the JIT compiler. JIT编译器还可能优化了(据说)冗余引用。 (Or maybe it isn't optimized away ... because they have concluded that the redundancy leads to faster execution on average .) Or maybe the actual implementation of the JVM 1 is just different. (或者可能没有对其进行优化……因为他们得出结论,冗余平均可以提高执行速度。)或者也许JVM 1的实际实现是不同的。

Bear in mind that the JVM spec is describing an idealized stack frame. 请记住,JVM规范描述的是理想的堆栈框架。 The actual implementation may be different ... provided that it behaves the way that the spec says it should. 实际的实现方式可能会有所不同……只要其行为符合规范要求。


On @EJP's point on normativeness, the only normative references for Java are the JLS and JVM specifications, and the Javadoc for the class library. 就@EJP的规范性而言,Java的唯一规范性引用是JLS和JVM规范,以及类库的Javadoc。 You can also consult the source code of the JVM itself. 您还可以查阅JVM本身的源代码。 The specifications say what should happen, and the code (in a sense) says what does happen. 规格说发生什么,代码(在某种意义上)说的话确实会发生。 An article you might find in a published paper or a web article is not normative, and may well be incorrect or out of date. 您可能在已发表的论文或网络文章中找到的文章不是规范性的,并且很可能不正确或已过时。


1 - The actual implementation may vary from one version to the next, or between vendors. 1-实际的实现可能因版本不同而异,或在供应商之间有所不同。 Furthermore, I have heard of a JVM implementation where a bytecode rewriter transformed from standard bytecodes to another abstract machine language at class load time. 此外,我听说过JVM实现,其中在类加载时,字节码重写器从标准字节码转换为另一种抽象机器语言。 It wasn't a great idea from a performance perspective ... but it was certainly within the spirit of the JVM spec. 从性能的角度来看,这不是一个好主意……但是,这当然符合JVM规范的精神。

The stack frame will contain the "current class constant pool reference" and also it will have the reference to the object in heap which in turn will also point to the class data. 堆栈框架将包含“当前类常量池引用”,并且还将具有对堆中对象的引用,而该对象又将指向类数据。 Is this not redundant?? 这不是多余的吗?

You missed the precondition of that statement, or you misquoted it, or it was just plainly wrong where you saw it. 您错过了该声明的前提条件,或者您引用了错误的语句,或者在您看到它的地方显然是错误的。

The "reference to the object in heap" is only added for non-static method, and it refers to the hidden this parameter. 仅对非静态方法添加“对堆中对象的引用”,它引用隐藏的this参数。

As it says in section " Local Variables Array ": 就像在“ 局部变量数组 ”部分中所说的那样:

The array of local variables contains all the variables used during the execution of the method, including a reference to this , all method parameters and other locally defined variables. 局部变量数组包含方法执行期间使用的所有变量,包括this的引用,所有方法参数和其他局部定义的变量。 For class methods (ie static methods) the method parameters start from zero, however, for instance method the zero slot is reserved for this . 对于类方法(即静态方法),方法参数从零开始,但是, 例如method, this保留了零槽

So, for static methods, there is no redundancy. 因此,对于静态方法,没有冗余。

Could the constant pool reference be eliminated when this is present? 能当常量池引用被淘汰this是存在? Yes, but then there would need to be a different way to locate the constant pool reference, requiring different bytecode instructions, so that would be a different kind of redundancy. 是的,但是然后需要一种不同的方式来定位常量池引用,这需要不同的字节码指令,因此这将是另一种冗余。

Always having the constant pool reference available in a well-known location in the stack frame, simplifies the bytecode logic. 常量池引用始终在堆栈帧中的一个众所周知的位置中可用,从而简化了字节码逻辑。

There are two points here. 这里有两点。 First, there are static methods which are invoked without a this reference. 首先,有一些static方法在没有this引用的情况下被调用。 Second, the actual class of an object instance is not necessarily the declaring class of the method whose code we are actually executing. 其次,对象实例的实际类不一定是我们实际执行其代码的方法的声明类。 The purpose of the constant pool reference is to enable resolving of symbolic references and loading of constants referenced by the code. 常量池引用的目的是实现符号引用的解析和代码引用的常量的加载。 In both cases, we need the constant pool of the class containing the currently executed code, even if the method might be inherited by the actual class of the this reference (in case of a private method invoked by another inherited method, we have a method invoked with a this instance of a class which formally does not even inherit the method). 在这两种情况下,我们都需要包含当前执行代码的类的常量池,即使该方法可能被this引用的实际类继承(在private方法被另一个继承的方法调用的情况下,我们也有一个方法使用类的this实例调用, this实例甚至不会继承该方法。

It might even be the case that the currently executed code is contained in an interface, so we never have instances of it, but still a class file with a constant pool which must be available when executing the code. 甚至可能是当前执行的代码包含在接口中的情况,因此我们永远不会有它的实例,但是仍然有一个带有常量池的类文件,执行该代码时必须可用。 This does not only apply to Java 8 and newer, which allow static and default methods in interfaces; 这不仅适用于Java 8和更高版本,后者允许在接口中使用static方法和default方法。 earlier versions also might need to execute the <clinit> method of an interface to initialize its static fields. 早期版本可能还需要执行接口的<clinit>方法来初始化其static字段。

By the way, even if an instance method is invoked with an object reference associated with this in its first local variable, there is no requirement for the bytecode instructions to keep it there. 顺便说一句,即使实例方法是在其第一个局部变量中使用与this对象相关联的对象引用来调用的,也不需要字节码指令将其保持在该位置。 If not needed, it might get overwritten by an arbitrary value, reusing the variable slot for other purposes. 如果不需要,它可能会被任意值覆盖,从而将变量插槽重新用于其他目的。 This does not preclude that subsequent instructions need the constant pool, which, as said, does not need to belong to the actual class of this anyway. 这并不排除随后的指令所需要的常量池,正如所说,并不需要属于实际的类this反正。

Of course, that pool reference is a logical construct anyway. 当然,该池引用无论如何都是逻辑构造。 Implementations may transform the code to use a shared pool or not to need a pool at all when all references have been resolved already, etc. After inlining, code may not even have a dedicated stack frame anymore. 当所有引用都已经解析后,实现可以将代码转换为使用共享池,或者根本不需要池,等等。在内联之后,代码甚至可能不再具有专用的堆栈框架。

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

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