V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Sunhcer
V2EX  ›  Java

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

  •  
  •   Sunhcer · 2022-04-27 07:54:00 +08:00 via Android · 2676 次点击
    这是一个创建于 723 天前的主题,其中的信息可能已经有所发展或是发生改变。
    第 1 条附言  ·  2022-04-27 09:03:52 +08:00
    同时关于 jdk8 中运行时常量池的位置也有两种说法,一种称在堆区,,另外一种称在元空间…
    关于三种常量池的位子,越搜索越迷惑…
    18 条回复    2022-05-05 16:14:34 +08:00
    xuanbg
        1
    xuanbg  
       2022-04-27 08:47:09 +08:00
    当一个类被加载并且它在 JVM 中的运行时表示正在准备时,它的类加载器会分配元空间来存储类的元数据。所以很明显就是每个类一个元空间。
    Sunhcer
        2
    Sunhcer  
    OP
       2022-04-27 09:05:00 +08:00 via Android
    @xuanbg 我可以参考什么文献来证实这种说法吗?其实对于运行时常量池在堆区还是元空间也比较迷惑
    xuanbg
        3
    xuanbg  
       2022-04-27 09:12:10 +08:00
    常量池在元空间。因为常量和对象无关,所以 JVM 的设计就是把常量放元空间以节省内存。
    xuanbg
        4
    xuanbg  
       2022-04-27 09:27:05 +08:00
    https://wiki.openjdk.java.net/display/HotSpot/Metaspace
    这个算不算权威的参考文档?
    JasonLaw
        5
    JasonLaw  
       2022-04-27 10:36:53 +08:00 via iPhone
    A1exlee
        6
    A1exlee  
       2022-04-27 11:14:50 +08:00
    放在堆里的应该说的是字符串池,字符串池从 1.7 开始就从方法区移到堆里了。运行时常量池还是在元空间里
    Sunhcer
        7
    Sunhcer  
    OP
       2022-04-27 13:08:05 +08:00 via Android
    @JasonLaw 感谢回复,我浏览了对于方法区的描述,这个版本的描述是否适用于 jdk8 呢?按文档的说法,常量在方法区,8 中方法区的实现是元空间,那就是说运行时常量池还是在元空间的嘛

    @xuanbg 权威,看不太懂,我这样阐述是否有问题呢?元空间内存角度上是一片动态扩展的内存区域,不同的类加载器在这片内存空间划分各自的领域,同一个类加载器加载的 class 元空间都在同一片区域,但是这里没有找到关于运行时常量池的描述,依旧不确定是一个还是多个
    JasonLaw
        8
    JasonLaw  
       2022-04-27 13:31:07 +08:00 via iPhone
    @Sunhcer #7 具体的 JVM 实现要看文档,这本书更多的是在讲 JVM specification 。我也没怎么研究具体的 JVM 实现,sorry ,解答不了你的疑问。
    weivi
        9
    weivi  
       2022-04-27 15:25:22 +08:00
    可以去了解一下字节码文件的结构,其中就包括运行时常量池,可以在一定程度上解决你的疑问
    Sunhcer
        10
    Sunhcer  
    OP
       2022-04-27 15:45:25 +08:00 via Android
    @weivi 类文件常量池跟运行时常量池不同吧
    weivi
        11
    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
        12
    ikas  
       2022-04-27 16:23:04 +08:00   ❤️ 1
    首先你先要分清楚 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
        13
    Sunhcer  
    OP
       2022-04-27 20:44:10 +08:00
    @weivi 是不同的,我跟倾向于这种说法:
    class 文件常量池存储的是当 class 文件被 java 虚拟机加载进来后存放在方法区的一些字面量和符号引用,字面量包括字符串,基本类型的常量。
    运行时常量池是当 class 文件被加载完成后,java 虚拟机会将 class 文件常量池里的内容转移到运行时常量池里,在 class 文件常量池的符号引用有一部分是会被转变为直接引用的。
    Sunhcer
        14
    Sunhcer  
    OP
       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
        15
    weivi  
       2022-04-28 09:18:18 +08:00
    @Sunhcer 你说的这个文件常量池是记录在字节码文件中的,是保存于磁盘上的数据,类加载完成以后其实和 jvm 就没什么关系了。运行时常量池是根据这些文件上的数据,在内存里面形成的数据。我认为这俩本质上就是一个东西,只不过是同一种数据的两种形式而已,一种是磁盘中的形式,一种是主存中的形式。
    Sunhcer
        16
    Sunhcer  
    OP
       2022-04-29 07:48:05 +08:00 via Android
    @weivi 同一种来源的数据在不同阶段的不同呈现,这样说更准确; 来源上是一样,但数据不一样:打个比喻就像是,一个是带占位符的短信模板,一个是填充好的短信
    weivi
        17
    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
        18
    Aresxue  
       2022-05-05 16:14:34 +08:00
    目前每个 class 独立一个, 但官方有意图想做到一个 jar 中所有类共享一个常量池,至于全局一个可能有些弊大于利不是很说得准。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   925 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 22:11 · PVG 06:11 · LAX 15:11 · JFK 18:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.