常量池
java文件编译成.class字节码文件后,会生成一个Constant pool的类目,这就是常量池。它存储在磁盘上,比如我的是D盘目录下。
符号引用包括
-
类和接口的全限定名
#2 = Class #63 // java/util/ArrayList
-
字段的名称和描述符
#4 = Fieldref #18.#64 // com/xxx/config/UrlConfig.captchaUrl:Ljava/util/List;
-
方法的名称和描述符
#3 = Methodref #2.#62 // java/util/ArrayList."<init>":()V
运行时常量池
JVM将.class文件加载后,在方法区会开辟一个运行时常量池,将Constant pool复制到运行时常量池中,在方法被调用后,将运行时常量池的符号引用,转换为虚拟机栈帧中的直接引用,即内存中的真实地址。
JVM为每一个加载的类和接口创建并维护一个运行时常量池,通过索引访问。
字符串常量池
为避免频繁的创建字符串带来的性能损耗,JVM为字符串开辟了字符串常量池,类似于缓存区。存在于JVM堆中
String s1 = "123";
String s2 = "123";
System.out.println(s1 == s2); // true
参考:https://blog.csdn.net/weixin_42679575/article/details/128021153
字符串常量池位置变迁
-
Jdk1.6及之前: 有永久代, 运行时常量池在永久代,运行时常量池包含字符串常量池
-
Jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池从永久代里的运行时常量池分离到堆里
-
Jdk1.8及之后: 无永久代,运行时常量池在元空间,字符串常量池里依然在堆里
参考: https://www.cnblogs.com/dtyy/p/15881493.html
总结
- 常量池在.class文件的字节码中,在磁盘上
- 运行时常量池在JVM的方法区中,.class文件被加载进JVM后,复制常量池到运行时常量池,并将符号引用替换为直接引用;JVM为每一个加载的类和接口创建并维护一个运行时常量池,通过索引访问
- 字符串常量池存在于JVM堆中。