java - 解析后的引用(即针对符号引用的直接内存地址)存储在 JVM 中的位置?

标签 java jvm resolution dynamic-linking symbolic-references

我研究过 JVM(尤其是 JDK 8 版本),在研究类链接时,我还没有弄清楚从解析中的符号引用确定的直接内存地址在哪里。

解析有好几种,比如type(class/interface)、field、method等,这里我只是做了一个class的例子来简单说明一下。

在JVM规范中,有一些词。

5.1 The Run-Time Constant Pool The Java Virtual Machine maintains a per-type constant pool (§2.5.5), a run-time data structure that serves many of the purposes of the symbol table of a conventional programming language implementation. The constant_pool table (§4.4) in the binary representation of a class or interface is used to construct the run-time constant pool upon class or interface creation (§5.3). All references in the run-time constant pool are initially symbolic.



规范说,所有引用最初都是符号引用。

这是一个示例 Main 类。
public class Main {
    public static void main(String[] args) {
        Object obj = new Object();
    }
}

这是 Main 类的常量池信息。
Constant pool:
#1 = Methodref          #2.#12         // java/lang/Object."<init>":()V
#2 = Class              #13            // java/lang/Object
#3 = Class              #14            // Main
#4 = Utf8               <init>
#5 = Utf8               ()V
#6 = Utf8               Code
#7 = Utf8               LineNumberTable
#8 = Utf8               main
#9 = Utf8               ([Ljava/lang/String;)V
#10 = Utf8               SourceFile
#11 = Utf8               Main.java
#12 = NameAndType        #4:#5          // "<init>":()V
#13 = Utf8               java/lang/Object
#14 = Utf8               Main
{
  public Main();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method     java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #2                  // class java/lang/Object
         3: dup
         4: invokespecial #1                  // Method java/lang/Object."<init>":()V
         7: astore_1
         8: return
      LineNumberTable:
        line 3: 0
        line 4: 8
}
SourceFile: "Main.java"

4.4.1 The CONSTANT_Class_info Structure
The CONSTANT_Class_info structure is used to represent a class or an > interface:
CONSTANT_Class_info {
   u1 tag;
   u2 name_index;
}



这里,Object 类在 Main 类的 main 方法中被引用。在 Main 类中,从不引用 Object 类。(当命令 java Main 刚刚执行时;)这意味着 Object Class entry(here, #2: CONSTANT_Class_info structure.)在 Main 的常量池中有 name_index #13。 #13 是包含对象类名称的 CONSTANT_Utf8_info 结构,#13 是对象类的符号引用。(老实说,我可能不确定这个 Utf8 常量池条目是 #2(对象的类池条目)的符号引用)

当 JVM 的执行引擎只执行一个字节码时,该字节码具有 Object 类的引用(在这个类中,0: new #2),#2 引用 #13(符号引用)。所以需要解析到JVM中Method Area上的Object Class的直接地址。并且发生类解析。

这是问题。
我已经阅读并搜索了 JVM 规范、博客、文章,但我找不到 JVM 中符号引用存储的已解析直接内存地址的位置。

我在 blog 中找到了一些信息, 它说,

Binding is the process of the field, method or class identified by the symbolic reference being replaced by a direct reference, this only happens once because the symbolic reference is completely replaced.



它说,已更换 .
在#2常量池条目中,Object类的符号引用存储在CONSTANT_Class_info结构的name_index(u2 type)字段中。

name_index 字段的值是不是变成了对象类的直接内存地址(可能在方法区的对象类的运行时常量池中)????

如果没有,直接地址存储在哪里?

请给我答案。谢谢你。

最佳答案

规范没有说明 JVM 在哪里存储解析的常量池条目。这是特定于实现的细节。

在 HotSpot JVM 中,常量池驻留在元空间中。它由两个相关的数组组成:一个标签数组和一个值数组。标签描述了相应值的类型。但这些是 不是 JVMS §4.4 中定义的相同的标签. JVM 在类文件解析阶段用自己的标签填充常量池。

有 4 种不同类型的常量池条目表示对 Java 类的引用:

  • JVM_CONSTANT_ClassIndex最初包含一个带有类名的常量池 Utf8 条目的整数索引。
  • JVM_CONSTANT_UnresolvedClass .常量池初始内容加载完毕后,JVM变化JVM_CONSTANT_ClassIndex标签到 JVM_CONSTANT_UnresolvedClass并用符号名称替换相应的 cp 条目。
  • JVM_CONSTANT_UnresolvedClassInError表示与 JVM_CONSTANT_UnresolvedClass 相同,但表示类解析尝试失败。
  • JVM_CONSTANT_Class是已解析类的内部表示的原始地址。

  • 因此,您的猜测是正确的:在常量池解析期间,HotSpot JVM 会就地修改 cp 条目并更改相应的 cp 标签。即JVM_CONSTANT_UnresolvedClass变成 JVM_CONSTANT_Class ,并且符号引用被替换为同一常量池值数组中的直接地址。

    您可以在 ConstantPool::klass_at_impl 中找到实现.

    关于java - 解析后的引用(即针对符号引用的直接内存地址)存储在 JVM 中的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53612470/

    相关文章:

    java - java中的classloader本身就是一个类那么谁来加载classloader类呢?

    java - 在 Java 中,是否可以增加 JVM 的可用内存和/或杀死其他 Java 程序?

    machine-learning - 图像的空间分辨率和 CNN 架构的大小之间有什么关系?

    android - 用于平板电脑的平板电脑可绘制文件夹

    java - 使用 BeanItemContainer 添加表列

    java - Java 读取文件时出错

    java - CloudFoundry 一般使用哪些电子邮件服务?

    java - JVM 的 "-server"选项是否需要成为第一个选项?

    selenium - Windows 任务计划程序中模式 "Run whether user is logged on or not"的屏幕分辨率

    java - 在 gridview 中缩放 imageview 时的空白