彻底搞清楚class常量池、运行时常量池、字符串常量池
常量池-静态常量池
也叫 class文件常量池,主要存放编译期生成的各种字面量(Literal)和符号引用(Symbolic References)。
- 字面量:例如文本字符串、fina修饰的常量。
(
- 整数型字面量,例如1、2、3、100等。
- 浮点型字面量,例如1.3、1.2、4.6等。
- 字符型字面量,例如’a’、‘b’、'\n’等。
- 布尔型字面量,例如true和false。
- 字符串型字面量,例如"abc"、"hello"等。
)
int b = 2;
int c = "abcdefg";
- 符号引用:
(
- 类和接口的全限定名
- 字段的名称和描述符
- 方法的名称和描述符
- 方法句柄和方法类型
- 动态调用点和动态调用点限定名
)
// 第3部分,常量池信息
Constant pool:
常量池-运行时常量池
- 当类加载到内存中后,JVM就会将class常量池中的内容存放到运行时常量池中;运行时常量池里面存储的主要是编译期间生成的字面量、符号引用等等。
- 类加载在链接环节的解析过程,会符号引用转换成直接引用(静态链接)。此处得到的直接引用也是放到运行时常量池中的。
- 运行期间可以动态放入新的常量。
常量池-字符串常量池
字符串常量池,也可以理解成运行时常量池分出来的一部分。类加载到内存的时候,字符串会存到字符串常量池里面。利用池的概念,避免大量频繁创建字符串。
- JDK6时字符串常量池位于运行时常量池,JDK7挪到堆中。
Hotspot8之前,使用持久代实现方法区,由于持久代内存不好估算,很容易到值OOM:Perm Gen异常。而元空间是本地内存,取决于操作系统分配内存。
字符串常量池位置变迁
Jdk1.6及之前: 有永久代, 运行时常量池在永久代,运行时常量池包含字符串常量池
Jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池从永久代里的运行时常量池分离到堆里
Jdk1.8及之后: 无永久代,运行时常量池在元空间,字符串常量池里依然在堆里