根据以下链接,java堆栈帧包含局部变量、操作数堆栈和当前类常量池引用。http://blog.jamesdbloom.com/JVMInternals.html
也来自Oracle "Structure of 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将指向堆中的对象,而堆中的对象将具有指向本田类数据的指针。堆栈帧还将具有当前的类常量引用。这是正确的吗?如果没有,请对此进行一些说明。
发布于 2018-05-13 08:33:31
堆栈帧将包含“当前类常量池引用”,它还将具有对堆中对象的引用,而堆中的对象也将指向类数据。这不是多余的吗??
你忽略了这句话的前提条件,或者你错误地引用了它,或者你看到它的地方显然是错误的。
只为非静态方法添加“堆中对象的引用”,它是指隐藏的this参数。
正如“Local Variables Array”一节中所说的:
局部变量数组包含方法执行期间使用的所有变量,包括对
this的引用、所有方法参数和其他本地定义的变量。对于类方法(即静态方法),方法参数从零开始,但是,对于实例方法,将为this. 预留零位置
因此,对于静态方法,没有冗余。
当存在this时,是否可以消除常量池引用?是的,但接下来需要一种不同的方法来定位常量池引用,需要不同的字节码指令,因此这将是一种不同类型的冗余。
总是将常量池引用放在堆栈帧中众所周知的位置,这简化了字节码逻辑。
发布于 2018-05-14 19:57:42
这里有两点。首先,有一些在没有this引用的情况下调用的static方法。其次,对象实例的实际类不一定是我们实际执行其代码的方法的声明类。常量池引用的目的是允许解析符号引用和加载代码引用的常量。在这两种情况下,我们都需要包含当前执行代码的类的常量池,即使该方法可能由this引用的实际类继承(在由另一个继承的方法调用的private方法的情况下,我们有一个方法被正式地不继承该方法的类的this实例调用)。
甚至可能的情况是,当前执行的代码包含在接口中,所以我们永远不会有它的实例,但仍然是一个具有常量池的类文件,在执行代码时必须可用。这不仅适用于Java8和更高版本,它们允许在接口中使用static和default方法;早期版本可能还需要执行接口的<clinit>方法来初始化其static字段。
顺便说一句,即使实例方法是通过与其第一个局部变量中的this相关联的对象引用来调用的,也不需要字节码指令将其保留在那里。如果不需要,它可能会被任意值覆盖,重用变量slot用于其他目的。这并不排除后续指令需要常量池,如前所述,常量池不需要属于this的实际类。
当然,那个池引用无论如何都是一个逻辑结构。实现可以将代码转换为使用共享池,或者当所有引用都已解析时根本不需要池,等等。在内联之后,代码甚至可能不再具有专用的堆栈框架。
https://stackoverflow.com/questions/50311664
复制相似问题