78

我目前正在尝试更深入地研究 Java 虚拟机的规范。我一直在在线阅读 Inside the JVM book,其中有一个我似乎无法理解的令人困惑的抽象:常量池。这是本书的摘录:

对于它加载的每种类型,Java 虚拟机都必须存储一个常量池。常量池是类型使用的一组有序常量,包括文字(字符串、整数和浮点常量)和对类型、字段和方法的符号引用。常量池中的条目由索引引用,很像数组的元素。因为它持有对一个类型使用的所有类型、字段和方法的符号引用,所以常量池在 Java 程序的动态链接中起着核心作用

总的来说,我对上述和 CP 有几个问题:

  1. CP 是否位于.class每种类型的文件中?
  2. 作者所说的“符号引用”是什么意思?
  3. 用简单的英语来说,常量池的目的是什么?
4

5 回答 5

93

常量池是.class文件(及其内存表示)的一部分,其中包含运行该类代码所需的常量。

这些常量包括程序员指定的文字和编译器生成的符号引用。符号引用基本上是从代码中引用的类、方法和字段的名称。JVM 使用这些引用将您的代码链接到它所依赖的其他类。

例如下面的代码

System.out.println("Hello, world!");

产生以下字节码(javap输出)

0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;              
3:   ldc     #3; //String Hello, world!                                                  
5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

#n这里是对常量池的引用。#2是对System.out字段的符号引用,#3Hello, world!字符串并且#4是对PrintStream.println(String)方法的符号引用。

如您所见,符号引用不仅仅是名称 - 例如,对方法的符号引用还包含有关其参数 ( Ljava/lang/String;) 和返回类型 ( Vmeans void) 的信息。

您可以通过为该类运行来检查该类的常量池javap -verbose

于 2012-04-18T13:25:33.640 回答
78

我认为了解如何使用图表构建框架会有所帮助。

在此处输入图像描述

帧是操作数(操作指令)所在的位置,也是动态链接发生的位置。可以说,这是一种速记方式,使用常量池来跟踪类及其成员。

每个帧都包含对运行时常量池的引用。引用指向为该帧执行的方法的类的常量池。此参考有助于支持动态链接。

C/C++ 代码通常被编译为一个目标文件,然后将多个目标文件链接在一起以产生一个可用的工件,例如可执行文件或 dll。在链接阶段,每个目标文件中的符号引用被替换为相对于最终可执行文件的实际内存地址。在 Java 中,这个链接阶段是在运行时动态完成的。

编译 Java 文件时,对变量和方法的所有引用都作为符号引用存储在类的常量池中。符号引用是逻辑引用,而不是实际指向物理内存位置的引用。

这是James Blooms JVM Internals的链接,了解更多详细信息。

于 2013-12-03T17:24:19.280 回答
9

用简单的英语来说,常量池的目的是什么?

CP 是一个非常独特的存储区域,用于存储常量值以减少冗余:

System.err.println("Hello");
System.out.println("Hello");

在 CP 中只有一个 String 对象“Hello”,编译器在两行中都替换为同一个引用。您的 .class 文件仅包含一个 Hello 字符串。(其他类型相同)。

CP 是否位于每种类型的 .Class 文件中?

是的,看这里:http ://en.wikipedia.org/wiki/Java_class_file

于 2012-04-18T13:15:23.420 回答
2
于 2015-03-01T13:01:37.443 回答
0

它可能被解释为浏览器的浏览历史,减少每次查找或构建的需要

于 2020-08-05T08:53:26.500 回答