Java常量池的目的是什么?


71

我目前正在尝试更深入地研究Java虚拟机的规范。我一直在在线阅读《 JVM内幕》,其中有一个我似乎无法理解的令人困惑的抽象:常量池。这是本书的摘录:

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

关于以上内容和CP,我有几个问题:

  1. CP是否位于.class每种类型的文件中?
  2. 作者“符号参考”是什么意思?
  3. 用简单的英语讲,恒定池的目的是什么?

Answers:


75

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

在此处输入图片说明

框架是操作数(操作指令)所在的位置,也就是动态链接发生的位置。可以这么说,这是使用常量池跟踪类及其成员的一种简便方法。

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

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

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

这是指向James Blooms JVM Internals的链接,以获取更多详细信息。


“编译Java类时...”?.class文件是否已编译为Java代码?
Koray Tugay,2015年

1
是的,.java文件在编译时会变成.class文件。
James Drinkard

他所有的联系都中断了。稍后再检查,看看他是否再次将其重新发布。
James Drinkard '16

链接再次固定。
James Drinkard '16

“操作数(操作说明)...”。操作数与建议的操作指令不同。对?
Yamcha '17

88

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

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


1
@ axtavt-哇!很好的解释。看起来像在“#3是对PrintStream的象征性引用..”附近的一个错字。它不应该是#4
Hitesh israni 2012年

但是“ L”在“ Ljava / lang / String;”中的含义是什么??
JackWM 2012年

2
JVM基本上只创建一个运行时常量池,对吗?还是每个.class文件都有单独的常量池?
2013年

1
另外,字符串实习生池是否是运行时常量池的一部分?
2013年

3
每个类文件中都有一个常量池。它由编译器创建。JVM在运行时解析CP的引用。字符串实习生池是VM内的一个区域。
Matthias Braun 2014年

9

用简单的英语讲,恒定池的目的是什么?

CP是一个存储区,非常独特的常数值被存储以减少冗余:

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

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

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

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


1
您是否可以在符号链接上进一步扩展?我认为这些是CP最重要的部分
Bober02 '04

2

首先给出示例,以了解字符串常量池的含义

   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-然后找到另一个变量s2,它引用了相同的字符串文字“ prasad”

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

在此处输入图片说明

我希望这会有所帮助

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


4
没有“字符串常量池”之类的东西。每个类文件中都存在“常量池”,并且对于JVM存在内部字符串的“字符串池”。
Keenle 2015年

是的,我的意思是字符串池,谢谢您的评论
Mina Fawzy 2015年

0

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.