当前位置: 首页 > 知识库问答 >
问题:

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

谷梁镜
2023-03-14

根据以下链接,java堆栈框架包含本地变量、操作数堆栈和当前类常量池引用。http://blog.jamesdbloom.com/JVMInternals.html

同样来自Oracle“JVM结构”第2.6节。3.“动态链接-每个帧(§2.6)包含对当前方法类型的运行时常量池(§2.5.5)的引用,以支持方法代码的动态链接。”

我还读到堆中的对象也有一个指向类数据的指针/引用。https://www.artima.com/insidejvm/ed2/jvm6.html

堆栈帧将包含“当前类常量池引用”,它还将包含对堆中对象的引用,而堆中的对象反过来也将指向类数据。这不是多余的吗??

例如

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
  }
}

当执行h.run()时,jvm将创建一个新的堆栈帧,并将h推到堆栈帧上。h将指向堆中的对象,而堆中的对象又有一个指向Honda类数据的指针。堆栈帧还将具有当前类常量引用。这是正确的吗?如果没有,请说明这一点。

共有3个答案

莫乐
2023-03-14

这里有两点。首先,有静态方法,这些方法在没有引用的情况下调用。其次,对象实例的实际类不一定是我们实际执行其代码的方法的声明类。常量池引用的目的是支持解析符号引用和加载代码引用的常量。在这两种情况下,我们都需要包含当前执行代码的类的常量池,即使该方法可能被this引用的实际类继承(在另一个继承的方法调用的private方法的情况下,我们有一个方法是使用一个类的this实例调用的,该类在形式上甚至不继承该方法)。

甚至可能是当前执行的代码包含在接口中,因此我们从来没有它的实例,但仍然是一个具有常量池的类文件,在执行代码时必须可用。这不仅适用于Java

顺便说一下,即使在实例方法的第一个局部变量中调用了与this关联的对象引用,也不需要字节码指令将其保留在那里。如果不需要,它可能会被任意值覆盖,将变量槽用于其他目的。这并不排除后续指令需要常量池,正如所说,它不需要属于实际的this类。

当然,无论如何,池引用都是一个逻辑构造。实现可以将代码转换为使用共享池,或者当所有引用都已解析时根本不需要池,等等。内联后,代码甚至可能不再有专用的堆栈框架。

令狐宏伟
2023-03-14

堆栈帧将包含“当前类常量池引用”,它还将包含对堆中对象的引用,而堆中的对象反过来也将指向类数据。这不是多余的吗??

你错过了那句话的前提条件,或者你错误地引用了它,或者你看到它的地方完全错了。

“堆中对象的引用”仅为非静态方法添加,它引用隐藏的this参数。

正如“局部变量数组”一节所述:

局部变量数组包含方法执行过程中使用的所有变量,包括对的引用、所有方法参数和其他局部定义的变量。对于类方法(即静态方法),方法参数从零开始,但是,例如方法,零槽是为保留的。

因此,对于静态方法,没有冗余。

存在此时,是否可以消除常量池引用?是的,但是需要一种不同的方法来定位常量池引用,需要不同的字节码指令,因此这将是一种不同的冗余。

始终在堆栈帧中的已知位置提供常量池引用,可以简化字节码逻辑。

慕兴平
2023-03-14

这不是多余的吗??

也许它对于实例方法和构造函数来说是多余的。

对于静态方法或类初始化伪方法来说,它不是多余的。

JIT编译器也可能会优化(假定)冗余引用。(或者可能它没有被优化掉……因为他们得出结论,冗余平均会导致更快的执行。)或者JVM1的实际实现可能只是不同而已。

请记住,JVM规范描述的是一个理想化的堆栈框架。实际的实现可能不同。。。前提是它的行为符合规范要求。

关于@EJP关于规范性的观点,Java的唯一规范性参考是JLS和JVM规范,以及类库的Javadoc。您还可以参考JVM本身的源代码。规范说明了应该发生什么,而代码(在某种意义上)说明了发生了什么。你可能在发表的论文或网络文章中发现的文章不规范,很可能不正确或过时。

1-实际实施可能因版本而异,或因供应商而异。此外,我听说过JVM实现,其中字节码重写器在类加载时从标准字节码转换为另一种抽象机器语言。从性能的角度来看,这不是一个好主意。。。但这肯定符合JVM规范的精神。

 类似资料:
  • 我有vframe函数并生成了如下的汇编代码 如果我们看到从8到11行,我们没有在堆栈上推送p的地址,但汇编已经假设 如果我们希望某些参数不被破坏,我们会推送一些寄存器并将被调用者保存的寄存器移动到推送的寄存器。但是,在这种情况下,似乎不是。关于局部变量还有其他约定吗,比如i和

  • 问题内容: 当我在Intellij Idea中调试Java应用程序时,我在堆栈框架中看到所有变量,如下所示: “ @”后面的数字是什么意思?它不同于hashCode返回的内容。hashCode以十六进制表示形式返回数字2a134eca,等于整数表示形式705908426。数字77和705908426是不同的。 问题答案: @是自应用程序启动以来的对象计数编号。因此,@ 1012表示自应用启动以来创

  • 问题内容: 我知道常量池的概念以及JVM用于处理字符串文字的字符串常量池。但是我不知道JVM使用哪种类型的内存来存储String常量文字。堆栈还是堆?由于它的文字不与任何实例相关联,因此我假定它将存储在堆栈中。但是,如果没有任何实例引用该文字,则必须通过GC运行来收集文字(如果我错了,请纠正我),那么如果将其存储在堆栈中,该如何处理? 问题答案: 从技术上来说,答案都不是。根据Java虚拟机规范,

  • 本文向大家介绍Java 运行时堆栈机制,包括了Java 运行时堆栈机制的使用技巧和注意事项,需要的朋友参考一下 每次需要用Java运行进程,代码或线程时,都会创建运行时堆栈,以存储在执行线程时执行的操作。 运行时堆栈中的每个条目都称为堆栈帧或激活记录。流程调用函数后,将从运行时堆栈中删除其关联的数据。 一旦调用了所有函数,运行时堆栈将为空。这意味着需要将其从内存中删除。 此时,运行时堆栈被破坏,然

  • 问题内容: 我对Java不太了解。 我浏览了几个链接,发现博客上写着“ Java Primitives存储在堆栈上”,我觉得这取决于实例变量或局部变量。 经过几个链接后,我的结论是, 类变量(基元)作为对象包含的对象的一部分存储在堆中。 类变量– object(用户定义)–作为其包含的Object的一部分存储在堆中。对于参考对象和实际对象都是如此。 方法变量-基元-作为该堆栈框架的一部分存储在堆栈

  • 问题内容: 我有个问题 例如,当我在方法内部声明变量时会发生什么。 在堆栈或堆中的哪里分配了myShip参考? 我认为是在堆栈中,但由于我在阅读《 J2ME游戏编程》“ Java类已实例化到Java堆”上而感到困惑 所有Java类别? 提前致谢 问题答案: 是对对象的引用,位于方法调用堆栈上,称为“堆栈”。当一个方法被称为一个内存块被推到栈顶时,该内存块有空间容纳所有原语(int,float,bo