【问题标题】:Does String.intern has anything to to with JVM Run-Time Constant poolString.intern 与 JVM 运行时常量池有什么关系
【发布时间】:2022-01-17 15:25:13
【问题描述】:

根据jvms11,运行时常量池中有两种入口:符号引用,稍后可能会解析,静态常量,不需要进一步处理。运行时常量池中的静态常量也是根据每个条目的结构从constant_pool表中的条目导出的。

我的理解是 String.intern 与 JVM Run-Time Constant pool 无关,但是中国最伟大的程序员之一说String.intern“在 Run-Time Constant 池中放一些东西在运行时” 在他的畅销书中。我们为此争论了很久,都无法说服对方。

所以我的问题是,String.intern 与 JVM 运行时常量池有什么关系吗?

这里是关于Rum-Time Constant pool的jvms5.1

【问题讨论】:

  • 没有。它与它完全无关。但与其争论……或者征求其他人的意见……您应该同时下载 OpenJDK 源代码并查看证据。
  • 常量池与 String poo 不同(intern() 使用)l,但它们在某种程度上 相关 ¹ 如所述通过this 和您链接到的同一部分的以下点(即:在类初始化完成之前,常量池中的字符串条目将与字符串池中的相应条目相同)|| ¹“有事可做”是问题

标签: java string jvm pool


【解决方案1】:

JVMS §5.1

Java 虚拟机为每个类和接口维护一个运行时常量池 (§2.5.5)。

术语“for each”表示不存在一个运行时常量池,但每个类或接口都有自己的专用池。后面的句子更清楚地表明,这个数据结构对应于一个类文件的常量池。

类或接口 (§4.4) 的二进制表示形式的 constant_pool 表用于在类或接口创建时构造运行时常量池 (§5.3)。

应该清楚的是,这种按类结构与用于在整个运行时规范化字符串实例的单一全局数据结构不同。

但是由于类文件中字符串常量的所有使用都表示为类文件常量池的索引,然后用于构造类的运行时常量池,这些使用与全局数据结构之间存在关系.如上所述within §5.1

运行时常量池中的静态常量也是根据每个条目的结构从constant_pool表中的条目导出的:

  • 字符串常量是reference 到类String 的实例,并且派生自CONSTANT_String_info 结构(§4.4.3)。为了派生一个字符串常量,Java 虚拟机检查CONSTANT_String_info 结构给出的代码点序列:
    • 如果方法String.intern 先前已在类String 的实例上调用,该实例包含与CONSTANT_String_info 结构所给出的相同的Unicode 代码点序列,则字符串常量是reference String 类的相同实例。
    • 否则,将创建一个新的类String 实例,其中包含CONSTANT_String_info 结构给出的Unicode 代码点序列。字符串常量是新实例的reference。最后,在新实例上调用方法 String.intern

因此,正式地,与类中使用的字符串常量对应的 String 实例是该类的运行时常量池的一部分,但根据 String.intern 进行初始化,以确保每个类在其池中都有规范化的字符串实例。

但是这种关系只有一个方向。当应用程序代码显式调用String.intern() 时,它不会访问类的运行时常量池。甚至不清楚我们应该访问哪个运行时常量池。

所以intern() 与运行时常量池无关,至少与其他调用者无关。

混淆的来源是 JVM 用于实现intern() 的数据结构在 JVMS 或 JLS 中根本没有名称。所以,没有正式的名字,不同的名字就会出现在不同的媒体上。例如,API documentation of intern() 表示

一个字符串池,最初是空的,由 String 类私下维护。

它通常是某种哈希表,但术语“池”与其目的相符,并且由于它存在于运行时,因此人们提出容易与 JVMS §5.1 的运行时常量池混淆的术语也就不足为奇了.

因此,在与另一位开发人员展开激烈讨论之前,重要的是要澄清是否每个人都在谈论同一个池。


作为附录,我在上面说过String正式是运行时常量池的一部分,因为这涉及到实现的特定方面。

原则上,JVM 可以在创建池时使用 String 实例初始化类的运行时常量池的所有字符串条目。但正如 this answer 所展示的,广泛使用的 HotSpot JVM 并非如此,它在第一次使用而不是类初始化时查找或创建 String 实例。

这意味着运行时常量池包含某种形式的原始字符数据,而不是对String 实例的引用。一旦构造了String,它就会被代码引用和重用,但是运行时常量池是否被修改为现在引用String或字节码指令(ldc)保留它,无法观察到Java 应用程序。我们只能观察到,只要类存在,String 实例就不会被垃圾回收。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-20
    • 2014-06-01
    • 2012-01-31
    • 2016-08-22
    • 2010-12-31
    • 1970-01-01
    相关资源
    最近更新 更多