每天分享一个小知识————JVM内存区域之运行中常量池

运行时常量池:类的“动态小抄本”

1. 是什么?
  • 角色:方法区中的一块“动态笔记区”,存放类的字面量(如字符串、数字)和符号引用(如类名、方法名)。

  • 来源:编译时写入(从Class文件的常量池加载) + 运行时动态添加(如通过String.intern())。

  • 比喻:像一本随时可以补充笔记的课本——既有原本印刷的内容(编译期常量),也能手写添加新内容(运行期常量)。


2. Class文件常量池 vs 运行时常量池
  • Class文件常量池

    • 位置.class文件中。

    • 内容:固定的字面量(如"Hello")和符号引用(如java/lang/Object)。

    • 作用:告诉JVM“这个类需要用到哪些常量和其他类”。

  • 运行时常量池

    • 位置:方法区(JDK8前是永久代,JDK8后是元空间)。

    • 内容:Class文件常量池的副本 + 运行期动态加入的常量(如String.intern()生成的字符串)。

    • 动态性:可以随时往池子里加新内容!

示例

java

复制

String s1 = "Hello";              // "Hello"来自Class文件常量池  
String s2 = new String("World").intern(); // "World"通过intern()动态加入运行时常量池  

3. 符号引用 vs 直接引用
  • 符号引用:用“名字”表示目标(如java/lang/String)。

    • 类比:用“张三家的地址:XX小区1号楼”描述一个位置。

  • 直接引用:目标在内存中的实际地址(如0x7f3e8c)。

    • 类比:GPS坐标(纬度30.123, 经度120.456)。

JVM的转换过程
类加载时,JVM把符号引用解析为直接引用(把“XX小区1号楼”翻译成具体坐标),并存到运行时常量池。


4. 动态性示例:String.intern()
  • 作用:将字符串添加到运行时常量池,并返回池中的引用。

  • 场景:避免重复创建相同字符串,节省内存。

代码示例

java

复制

String s1 = new String("Hello");      // 在堆中创建新对象  
String s2 = s1.intern();              // 将"Hello"加入常量池(如果不存在)  
System.out.println(s1 == s2);         // false(s1在堆,s2指向常量池)  

String s3 = "Hello";  
System.out.println(s2 == s3);         // true(都指向常量池)  

5. 为什么会导致OutOfMemoryError(OOM)?
  • 触发条件:运行时常量池所在的方法区(或元空间)内存耗尽。

  • 典型场景

    • JDK8前:永久代容量有限(默认较小),频繁调用intern()加载大量字符串。

    • JDK8后:元空间默认无上限,但若系统内存不足,仍会OOM。

示例

java

复制

List<String> list = new ArrayList<>();  
while (true) {  
    String s = new String("疯狂添加" + i).intern(); // 不断往常量池塞字符串  
    list.add(s);  
}  

最终元空间(或永久代)被撑爆 → 抛出OOM!


总结对比表

特性Class文件常量池运行时常量池
存储位置.class文件中方法区(元空间/永久代)
内容编译期确定的字面量和符号引用Class常量池内容 + 运行期动态添加的常量
动态性固定不变可动态扩展(如intern()
内存限制无(文件大小限制)受方法区/元空间内存限制,可能OOM

一句话理解

运行时常量池是类的“动态小抄本”——原本抄写课本内容,运行时还能自己加笔记。但笔记本(方法区)写满了就会爆仓(OOM)!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值