【问题标题】:What is the purpose of the Java Constant Pool?Java 常量池的目的是什么?
【发布时间】:2012-04-29 21:32:43
【问题描述】:

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

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

我有几个关于上述和一般CP的问题:

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

【问题讨论】:

    标签: java vm-implementation class-constants


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

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

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

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

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

      这里是James Blooms JVM Internals的链接了解更多详情。

      【讨论】:

      • "Java 类编译时..." ? .class 文件不是已经编译好的 Java 代码了吗?
      • 是的,.java 文件编译后变成.class 文件。
      • 他所有的链接都坏了。我稍后再回来看看他是否再次转发。
      • 链接又修复了。
      • “操作数(操作指令)...”。操作数与建议的操作指令不同。对吗?
      【解决方案3】:

      先举个例子来理解String常量池是什么意思

         public class StringConstantPool {
              public static void main(String[] args) {
                  String s = "prasad";
                  String s2 = "prasad";
           
                  System.out.println(s.equals(s2));
                  System.out.println(s == s2);
              }
          }
      

      输出将是

      true
      
      true 
      

      这里一步一步发生了什么

      1- 调用 JVM 时加载类。

      2- JVM 会查找程序中的所有字符串字面量。

      3- 首先,它找到引用文字“prasad”变量s,并在内存中创建它

      4- 对文字 “prasad” 的引用将被放置在字符串常量池内存中。

      5- 然后它找到另一个 variable s2 引用相同的字符串文字 “prasad”

      现在 JVM 已经找到一个字符串字面量“prasad”变量 s 和 s2 都将引用同一个对象,即 “prasad”。

      希望对你有帮助

      阅读更多 http://www.journaldev.com/797/what-is-java-string-pool

      【讨论】:

      • 没有“字符串常量池”之类的东西。每个类文件中都存在“常量池”,并且 JVM 中存在“字符串池”。
      • 是的,我的意思是字符串池,谢谢你的评论
      【解决方案4】:

      常量池是.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;)和返回类型(V 表示 void)的信息。

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

      【讨论】:

      • @axtavt-哇!很好的解释。看起来像“#3 is a symbolic reference to PrintStream..”附近的一个小错字不应该是#4
      • 但是“L”在“Ljava/lang/String;”中是什么意思? ?
      • JVM 创建的运行时常量池基本上只有一个,对吧?还是每个 .class 文件都有一个单独的常量池?
      • 另外,字符串实习池是运行时常量池的一部分吗?
      • 每个类文件中都有一个常量池。它由编译器创建。 JVM 在运行时解析 CP 的引用。字符串实习生池是虚拟机内部的一个区域。
      【解决方案5】:

      Constant Pool 的用途是什么,用简单的英语表示?

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

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

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

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

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

      【讨论】:

      • 您能否进一步扩展符号链接?我认为这些是CP最重要的部分
      猜你喜欢
      • 2014-05-20
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      • 1970-01-01
      • 2020-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多