元空间的运行时常量池究竟是全局一个还是每个 class 独立一个?网上众说纷纭,该如何求证?

2022-04-27 07:54:00 +08:00
 Sunhcer
2877 次点击
所在节点    Java
18 条回复
xuanbg
2022-04-27 08:47:09 +08:00
当一个类被加载并且它在 JVM 中的运行时表示正在准备时,它的类加载器会分配元空间来存储类的元数据。所以很明显就是每个类一个元空间。
Sunhcer
2022-04-27 09:05:00 +08:00
@xuanbg 我可以参考什么文献来证实这种说法吗?其实对于运行时常量池在堆区还是元空间也比较迷惑
xuanbg
2022-04-27 09:12:10 +08:00
常量池在元空间。因为常量和对象无关,所以 JVM 的设计就是把常量放元空间以节省内存。
xuanbg
2022-04-27 09:27:05 +08:00
https://wiki.openjdk.java.net/display/HotSpot/Metaspace
这个算不算权威的参考文档?
JasonLaw
2022-04-27 10:36:53 +08:00
A1exlee
2022-04-27 11:14:50 +08:00
放在堆里的应该说的是字符串池,字符串池从 1.7 开始就从方法区移到堆里了。运行时常量池还是在元空间里
Sunhcer
2022-04-27 13:08:05 +08:00
@JasonLaw 感谢回复,我浏览了对于方法区的描述,这个版本的描述是否适用于 jdk8 呢?按文档的说法,常量在方法区,8 中方法区的实现是元空间,那就是说运行时常量池还是在元空间的嘛

@xuanbg 权威,看不太懂,我这样阐述是否有问题呢?元空间内存角度上是一片动态扩展的内存区域,不同的类加载器在这片内存空间划分各自的领域,同一个类加载器加载的 class 元空间都在同一片区域,但是这里没有找到关于运行时常量池的描述,依旧不确定是一个还是多个
JasonLaw
2022-04-27 13:31:07 +08:00
@Sunhcer #7 具体的 JVM 实现要看文档,这本书更多的是在讲 JVM specification 。我也没怎么研究具体的 JVM 实现,sorry ,解答不了你的疑问。
weivi
2022-04-27 15:25:22 +08:00
可以去了解一下字节码文件的结构,其中就包括运行时常量池,可以在一定程度上解决你的疑问
Sunhcer
2022-04-27 15:45:25 +08:00
@weivi 类文件常量池跟运行时常量池不同吧
weivi
2022-04-27 16:21:24 +08:00
@Sunhcer 是同一个东西 ,下面的内容摘自周志明的《深入理解 java 虚拟机》第三版
----------------------------------------------------------------------------------------------------------
常量池中主要存放两大类常量:字面量( Literal )和符号引用( Symbolic References )。字面量比
较接近于 Java 语言层面的常量概念,如文本字符串、被声明为 final 的常量值等。而符号引用则属于编译
原理方面的概念,主要包括下面几类常量:
·被模块导出或者开放的包( Package )
·类和接口的全限定名( Fully Qualified Name )
·字段的名称和描述符( Descriptor )
·方法的名称和描述符
·方法句柄和方法类型( Method Handle 、Method Type 、Invoke Dynamic )
·动态调用点和动态常量( Dynamically-Computed Call Site 、Dynamically-Computed Constant )
ikas
2022-04-27 16:23:04 +08:00
首先你先要分清楚 jvm 规范,与 jvm 的具体实现
jvm 规范中:
1.方法区域在逻辑上是堆的一部分,但是并不要求方法区域的位置
2.运行时常量池都是从 Java 虚拟机的方法区域分配的

具体的 jvm 实现,比如 openjdk8+:
永久生成的部分内容移动到 Java 堆,其余内容移动到本机内存

参考
https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-2.html#jvms-2.5.4
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4
http://openjdk.java.net/jeps/122
Sunhcer
2022-04-27 20:44:10 +08:00
@weivi 是不同的,我跟倾向于这种说法:
class 文件常量池存储的是当 class 文件被 java 虚拟机加载进来后存放在方法区的一些字面量和符号引用,字面量包括字符串,基本类型的常量。
运行时常量池是当 class 文件被加载完成后,java 虚拟机会将 class 文件常量池里的内容转移到运行时常量池里,在 class 文件常量池的符号引用有一部分是会被转变为直接引用的。
Sunhcer
2022-04-27 20:50:24 +08:00
@ikas 厉害了,我在这里找到一句话似乎可以终结疑问;
https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-5.html

The Java Virtual Machine maintains a run-time constant pool for each class and interface (§2.5.5).
Java 虚拟机为每个类和接口维护一个运行时常量池; 那就是独立的喽
大佬,喝冰可乐!
weivi
2022-04-28 09:18:18 +08:00
@Sunhcer 你说的这个文件常量池是记录在字节码文件中的,是保存于磁盘上的数据,类加载完成以后其实和 jvm 就没什么关系了。运行时常量池是根据这些文件上的数据,在内存里面形成的数据。我认为这俩本质上就是一个东西,只不过是同一种数据的两种形式而已,一种是磁盘中的形式,一种是主存中的形式。
Sunhcer
2022-04-29 07:48:05 +08:00
@weivi 同一种来源的数据在不同阶段的不同呈现,这样说更准确; 来源上是一样,但数据不一样:打个比喻就像是,一个是带占位符的短信模板,一个是填充好的短信
weivi
2022-04-29 08:57:49 +08:00
@Sunhcer java 虚拟机规范关于运行时常量池介绍的第一句话。
-------------------------------------------------------------------------------------
A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4)
Aresxue
2022-05-05 16:14:34 +08:00
目前每个 class 独立一个, 但官方有意图想做到一个 jar 中所有类共享一个常量池,至于全局一个可能有些弊大于利不是很说得准。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/849474

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX