1. 面试题背后的JVM内存模型解析
当面试官抛出"String str = new String("abc")创建了几个对象"这个问题时,实际上是在考察你对JVM内存结构的理解深度。这个问题看似简单,却涉及字符串常量池、堆内存以及它们之间的交互机制。
1.1 字符串常量池的演变
字符串常量池在不同JDK版本中的位置有所变化:
- JDK6及之前:位于方法区(永久代)
- JDK7及之后:移动到堆内存中
这个变化带来了几个重要影响:
- 字符串常量池中的对象现在可以被垃圾回收
- 减少了永久代溢出的风险
- 字符串常量池的大小可以通过-XX:StringTableSize参数调整
提示:在JDK8中,虽然永久代被元空间(Metaspace)取代,但字符串常量池依然位于堆内存中。
1.2 堆内存与常量池的关系
理解堆内存和字符串常量池的关系是回答这个问题的关键:
- 字符串常量池:存储所有字面量形式的字符串
- 堆内存:存储所有通过new关键字创建的字符串对象
当代码中出现字面量"abc"时,JVM会先在字符串常量池中查找是否存在该字符串:
- 如果存在,直接返回常量池中的引用
- 如果不存在,则在常量池中创建该字符串对象
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 对象创建过程深度解析
2.1 常见情况:创建2个对象
当执行String str = new String("abc")时,如果常量池中不存在"abc",会经历以下步骤:
-
首先处理字面量"abc":
- JVM检查字符串常量池
- 未找到"abc",于是在常量池创建字符串对象O1
- 将"abc"存入常量池
-
处理new String():
- 在堆内存中分配新的字符串对象O2
- 将O1的字符数组复制到O2
- 返回O2的引用给str
这种情况下,总共创建了2个对象:1个在常量池(O1),1个在堆(O2)。
2.2 特殊情况:创建1个对象
如果常量池中已经存在"abc"(比如之前代码使用过该字面量),则:
-
处理字面量"abc":
- JVM在常量池中找到已有对象O1
- 直接使用O1
-
处理new String():
- 仍在堆内存中创建新对象O2
- 复制O1的字符数组到
