1. class文件常量池(class constant pool)
.java文件经过编译之后会生成.class文件保存到磁盘上,也被称为字节码文件,该文件内容主要分为两部分:方法字节码和常量池。常量池用于存放编译器生成的各种字面量和符号引用。 每个类都会生成自己的字节码文件,因此,每个类也都有一个class文件常量池。
字面量:
- 文本字符串
- 八种基本类型的值
- 被声明为final的常量等;
符号引用:
- 符号引用是相对于直接引用来说的,直接引用是计算机能看懂的物理地址,而符号引用是程序员能看懂的符号,比如类引用、方法引用,成员变量引用等。
2. 运行时常量池(runtime constant pool)
类加载时,把某个类的字节码文件从磁盘被加载到内存,JVM同时将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。
运行时常量池相比于class文件常量池更有动态性,在运行期间也可以将新的变量放入常量池中,而不局限于编译期。最主要的运用便是String类的intern()方法(该函数的详细解读可见本站的另一篇文章:intern()函数)
3. 全局字符串池(string pool)
类加载完成,经过验证,准备阶段之后在堆中生成驻留字符串的实例对象,然后将该字符串对象实例的 直接引用 存到字符串常量池中(整个JVM中只有一份)。在解析时,JVM把符号引用替换为直接引用,替换的过程就是运行时常量池拿符号引用查询全局字符串池中的直接引用。
三个常量池的工作搭配方法:
jvm在执行某个类(运行期)的时候,必须经过 加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。
程序的首先经过编译之后得到字节码,字节码的class常量池中包含一些符号引用;然后类加载,将class常量池中的符号引用转存到运行时常量池中;经过验证,准备阶段之后,在堆中生成驻留字符串的实例对象,然后将这些对象的引用存到全局字符串常量池中,也就是StringTable;最后在解析阶段,要把运行时常量池中的符号引用替换成直接引用,替换的依据就是向StringTable查询。
三个常量池分别在 Java内存区域的哪个位置
class文件常量池在字节码文件中,字节码文件在磁盘上,不在java的内存区域里。
- jdk1.6及之前,运行时常量池位于永久代(方法区的一种实现)内部;字符串常量池又在运行时常量池内部,存的是对象。
- jdk1.7,字符串常量池从永久代移至堆区,改存对象的引用值。运行时常量依然在永久代
- jdk1.8及之后,永久代被元空间取代了。运行时常量池跟着元空间从虚拟机内存迁到了PC本地内存(用以防止方法区频繁的OOM)
xie.infoq.cn/article/452… tangxman.github.io/2015/07/27/… zhuanlan.zhihu.com/p/55468381 www.nowcoder.com/questionTer… blog.csdn.net/zzzgd_666/a… blog.csdn.net/TomAndersen… www.zhihu.com/question/55… juejin.cn/post/684490…