运行时常量池 - 由运行时创建的变量填充?

Runtime constant pool - is filled up by variables created in runtime?

我不确定运行时常量池的某些属性。

运行时常量池,由常量池中的数据填充(来自 .class 文件,在 class 加载期间)。但它是否也由运行时创建的变量填充?还是在编译过程中将它们转换为文字,并存储在常量池中?

例如:

Integer i = new Integer(127);

被视为文字,因为转换为:

Integer i = Integer.valueOf(127);

在编译期间,存储在常量池中?

如果不是那样工作,是否有运行时常量池的运行时机制?

还有第二个问题:我在很多文章中都找到了这句话:"every class got Runtime constant pool",但是它是什么意思呢?是否有单个 RCP,它包含(例如)Integer 类型的所有应用程序对象,或者是否有每个 class 的单个 RCP,它包含在此 class 中出现的所有常量对象? (例如:Person,得到 age = Integer(18),和 isAdult = Boolean(true))。

问题 1 - 答案:否

整数包装器类型被缓存,而不是存储在常量池中。它们只是堆中的普通对象。 IntegerByte缓存是运行时优化,不是VM优化,也不是编译时优化。当它们的构造函数被调用以创建一个新的时,它们不会神奇地替换为缓存的。

首先,您从 new Integer(127)Integer.valueOf(127) 的翻译根本不正确,如 post 中所述。如果你做一些运行时验证,比如 System.out.println(Integer.valueOf(127) == new Integer(127));(打印 false),你会很快得出结论,无论你正在构造什么对象,使用 new 运算符总是创建一个新的,未缓存的对象。 (甚至 Strings,实际上在运行时常量 table 中,也需要实习才能获得对规范的引用。)

i 变量持有的只是指向堆中 Integer 对象的引用。如果您使用 valueOf,它将被缓存,反之亦然。


问题 2 - Anwser:每个 class 都有一个 RCP,但它们都在同一内存区域

RCPs are all stored in method area. Personally I don't know how JVM is implemented, but JVMS has stated:

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.

不过,即使从性能调整的角度来看,这也无关紧要,只要您不打算申请 Oracle 中的工作。

首先没有转换

Integer i = new Integer(127);

Integer i = Integer.valueOf(127);

这些结构完全不同。 new Integer(127) 保证在每次评估时产生一个新实例,而 Integer.valueOf(127) 保证在每次评估时产生相同的实例,因为 Integer.valueOf 保证 [=15] 中的所有值=] 范围。这是由 Integer.valueOf(int) 的实现处理的,与常量池无关。当然,它是特定于实现的,但是 OpenJDK 实现通过简单地 filling an array with references to these 256 instance the first time, this cache is accessed.

来处理这个问题

虽然每个 class 都有一个 constant pool in its class file 是正确的,但说每个 class 都有一个运行时常量池(独立)可能会产生误导。这又是一个 JVM 实现细节。虽然可以将每个 class 常量池 1:1 映射到运行时常量池,但合并生活在相同解析上下文中的 classes 的常量池显然是有意义的(即定义通过相同的 class 加载程序)到一个池中,这样就不需要多次解析相同的常量。尽管从概念上讲,每个 class 都有其池的运行时表示,即使它们没有以这种天真的形式实现。所以“每个class都有一个运行时常量池”这句话并没有错,但并不一定意味着每个class.

都会有这样一个数据结构

这会影响 classes、成员、MethodTypeMethodHandleString 实例,由 classes 的常量池引用,但是不是像 IntegerBoolean 这样的包装器类型,因为在常量池中没有这样的条目。池中的整数值是原始值,根本不存在布尔值。

这不能与全局 String 池引用文字的所有 String 个实例和 intern() 调用的结果相混淆。