解析后的引用(即相对于符号引用的直接内存地址)在解析后存储在JVM中的哪里?

emi*_*tar 6 java jvm resolution dynamic-linking symbolic-references

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

\n\n

解析有很多种,比如类型(类/接口)、字段、方法等,但我只是做了一个类的例子来简单解释。

\n\n

在JVM规范中,有一些词。

\n\n
\n

5.1 运行时常量池\n Java 虚拟机维护一个每种类型的常量池 (\xc2\xa72.5.5),这是一种运行时数据结构,可用于传统编程语言的符号表的许多用途实现。\n 类或接口的二进制表示形式中的constant_pool 表(\xc2\xa74.4) 用于在创建类或接口(\xc2\xa75.3) 时构造运行时常量池。运行时常量池中的所有引用最初都是符号性的。

\n
\n\n

规范中说,所有引用首先都是符号引用。

\n\n

这是一个示例主类。

\n\n
public class Main {\n    public static void main(String[] args) {\n        Object obj = new Object();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是主类的常量池信息。

\n\n
Constant pool:\n#1 = Methodref          #2.#12         // java/lang/Object."<init>":()V\n#2 = Class              #13            // java/lang/Object\n#3 = Class              #14            // Main\n#4 = Utf8               <init>\n#5 = Utf8               ()V\n#6 = Utf8               Code\n#7 = Utf8               LineNumberTable\n#8 = Utf8               main\n#9 = Utf8               ([Ljava/lang/String;)V\n#10 = Utf8               SourceFile\n#11 = Utf8               Main.java\n#12 = NameAndType        #4:#5          // "<init>":()V\n#13 = Utf8               java/lang/Object\n#14 = Utf8               Main\n{\n  public Main();\n    descriptor: ()V\n    flags: ACC_PUBLIC\n    Code:\n      stack=1, locals=1, args_size=1\n         0: aload_0\n         1: invokespecial #1                  // Method     java/lang/Object."<init>":()V\n         4: return\n      LineNumberTable:\n        line 1: 0\n\n  public static void main(java.lang.String[]);\n    descriptor: ([Ljava/lang/String;)V\n    flags: ACC_PUBLIC, ACC_STATIC\n    Code:\n      stack=2, locals=2, args_size=1\n         0: new           #2                  // class java/lang/Object\n         3: dup\n         4: invokespecial #1                  // Method java/lang/Object."<init>":()V\n         7: astore_1\n         8: return\n      LineNumberTable:\n        line 3: 0\n        line 4: 8\n}\nSourceFile: "Main.java"\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

4.4.1 CONSTANT_Class_info 结构
\n CONSTANT_Class_info 结构用于表示类或 > 接口:
\n CONSTANT_Class_info {
\n u1 tag;
\n u2 名称_索引;
\n}

\n
\n\n

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

\n\n

当 JVM 的执行引擎只执行一个具有对象类引用(在本类中为0: new #2)的字节码时,#2 引用#13(符号引用)。因此,需要将其解析为JVM中方法区上对象类的直接地址。并且发生类解析。

\n\n

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

\n\n

我在博客中找到了一些信息,它说:

\n\n
\n

绑定是由符号引用标识的字段、方法或类被直接引用替换的过程,这只发生一次,因为符号引用被完全替换。

\n
\n\n

\ n在#2常量池条目中,Object类的符号引用存储在CONSTANT_Class_info结构的name_index(u2 type)字段中。

\n\n

name_index字段的值是否更改为Object Class的直接内存地址(可能在方法区中Object clsas的运行时常量池中)???

\n\n

如果不是,直接地址存储在哪里?

\n\n

请给我答案。谢谢。

\n

apa*_*gin 1

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

\n\n

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

\n\n

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

\n\n
    \n
  • JVM_CONSTANT_ClassIndex最初包含带有类名的常量池 Utf8 条目的整数索引。
  • \n
  • JVM_CONSTANT_UnresolvedClass。当常量池的初始内容完全加载后,JVM将JVM_CONSTANT_ClassIndex标记更改为JVM_CONSTANT_UnresolvedClass符号名称并替换相应的cp条目。
  • \n
  • JVM_CONSTANT_UnresolvedClassInError与 的含义相同JVM_CONSTANT_UnresolvedClass,但表示类解析尝试失败。
  • \n
  • JVM_CONSTANT_Class是已解析类的内部表示的原始地址。
  • \n
\n\n

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

\n\n

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

\n