JVM中几个常量池的概念(常量池、运行时常量池与字符串常量池)

您所在的位置:网站首页 java中的常量池 JVM中几个常量池的概念(常量池、运行时常量池与字符串常量池)

JVM中几个常量池的概念(常量池、运行时常量池与字符串常量池)

2023-10-19 08:55| 来源: 网络整理| 查看: 265

在Java的内存分配中,经常听到很多关于常量池的描述,一开始对这些概念比较模糊,于是上网查阅各种资料,用最简单的语言描述以下这几个概念。

1、常量池 1.1、什么是常量池?

我们写的每一个Java类被编译后,就会形成一份class文件,class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic References)。如下图所示:

image.png

1.2、为什么需要常量池?

一个java源文件中的类、接口,编译后会产生一个字节码文件,而java中的字节码文件需要其他的数据支撑,通常这种数据很大,不能直接存放到字节码里面。所以把对这些数据的引用存放到常量池,在真正需要使用的时候,通过动态链接将符号引用转换为直接引用。

符号引用(Symbolic References):符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。方法名,类名,字段名都是符号引用

直接引用(Direct References):直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。如果有了直接引用,那么引用的目标一定是已经存在于内存中。

2、运行时常量池

常量池指的是字节码文件中的Constant pool部分,当字节码文件被加载到内存中之后,方法区中会存放字节码文件的constant pool相关信息,这时候就成为了运行时常量池。运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。此时不再是常量池中的符号地址了,这里换为真实地址。

另外,运行时常量池具有动态性。也就是在方法区中的运行时常量池是可以发生变化的。而常量池就不行,它是静态的,当编译生成字节码文件后就不变了。

3、全局字符串常量池(string pool也有叫做string literal pool)

全局字符串常量池(就是字符串常量池,全局我认为是强调只有一个,被所有类共享)里的内容是在类加载完成,经过验证,准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例的引用值存到string pool中(记住:string pool中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的)。 在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个哈希表,里面存的是驻留字符串(也就是我们常说的用双引号括起来的)的引用(而不是驻留字符串实例本身),也就是说在堆中的某些字符串实例被这个StringTable引用之后就等同被赋予了”驻留字符串”的身份。这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。

举例:

String str = new String("hello");

上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,同时,全局字符串常量中也有一份驻留字符串的引用,而”hello”这个字面量是放在方法区的。

总结 class常量池是在编译的时候每个class都有的,在编译阶段,存放的是常量的符号引用。 运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致。 全局字符串常量池在每个JVM中只有一份,存放的是字符串常量的引用值。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3