截图笔记中这里的intern方法的使用时针对jdk1.6
结果和1.7中String#intern方法不同,可以参考文末中链接中相关的内容
另外:
- 在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代
- 在JDK1.7 字符串常量池被从方法区拿到了堆中,这里没有提到运行时常量池,也就是说字符串常量池被单独拿到堆,运行时常量池剩下的东西还在方法区, 也就是hotspot中的永久代
- 在JDK1.8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆, 运行时常量池还在方法区,只不过方法区的实现从永久代变成了元空间(Metaspace)
下面这部分内容主要是结合视频学习过程中实操的笔记记录,有兴趣可读,没兴趣直接跳过截图到intern方法比较吧!
- 对于常量字符串,在编译的时候就会将这个字符存入常量池
常量池中其实有一个table表对象维护所有的字符串 - 对于 new String(“abc”)的理解:
有种说法new String会在堆中和常量池中创建两个对象,这种说法其实没错
因为括号里面出现的"abc"其实相当于String s1 = "abc"的作用,这个对象就已经存入了常量池 但是如果出现new String(“a”) + new String(“b”) + new String(“c”) 这种,那么常量池只有a b c 三个对象,但是并没有abc这个对象。对于 new String(str1); 这个时候str1的所代表的对象是不会存入常量池的,而是存入堆中 - 对于 String test = “a” + “b” + “c”:
这个时候常量池里面其实只有一个对象,因为 a b c 它们在编译的时候就会生成一个abc字符串, 所以只有一个对象被创建反编译过后成了 String test = “abc”:
同理:String s = new String(“abc” + “def”);反编译成为了 String s = new String(“abcdef”);也就是创建了两个对象
但是:String s = new String(“abc” + str); 就不一样了 - 对于变量字符串参与+运算
String s = “abc” + str;
因为编译期间无法确认str,所以不能以常量来计算,这个时候就得使用new来操作
但是如果 str 是 final 类型,那么又不一样了,他就是一个常量了,以后代码中出现的str都会被它的字符串来代替 - 常量池保存的是字符串还是字符串的引用?
其实回答这个问题需要区分jdk版本
jdk<=6 : 那么常量池中肯定保存的都是字符串
jdk>=7 : 那么常量池中保存可以是字符串,也可以是引用
那什么时候会出现保存引用呢?
这就需要了解jdk7以后,常量池被移到堆中,并且intern方法机制有改变,这个方法
在jdk7以前,机制是看常量池中有没有指定的字符串,如果没有则复制一份字符串到
常量池中;jdk7以后,区别是如果常量池没有则会把堆中的字符串的引用复制一份到
常量池中。
所以字符串可以保存在常量池中,也可以保存在堆中;
jdk7以后,常量池中可以保存字符串,也可以保存字符串的引用。
其实从图2 就可以得出一些结论:
a 字符串其实可以存储在两个地方,池和堆中都有存储,否则也不会出现intern这个方法去常量池中找有没有这个字符串,那说明有的字符串根本就不在池中
比如下面代码创建的对象都是在堆中
new String(String.valueOf(123))
new String("a") + new String("b")
-
对于String.intern方法(这个方法只有new对象才能调用)
jdk<7:则是将字符串本身在常量池中查找,如果有,则返回常量池中的引用,没有则在常量池中新建字符串本身,然后返回常量池的引用
jdk>=7:则是将字符串本身在常量池中查找,如果有,则返回常量池中的引用,这里没有变化,如果没有则会将堆中的引用传递给常量池,然后返回这个指向堆的引用 -
对于不同的版本的jdk常量池的位置(方法区也被叫做永久代)
jdk6:常量池放在方法区(永久代)中
jdk7:常量池放在堆中,方法区中的其余的还在方法区(永久代)
jdk8+:常量池放在堆中,方法区(永久代)被取消,被放在元空间
可以使用jdk8测试:
jvm参数:-Xmx20m -Xms20m -XX:-UseGCOverheadLimit
这里的-XX:-UseGCOverheadLimit是关闭GC占用时间过长时会报的异常
运行下面代码:
public static void main(String[] args) throws Throwable {
List<String> list = new ArrayList<String>();
int i=0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
异常信息是:java.lang.OutOfMemoryError: Java heap space
原文链接:https://blog.csdn.net/wodemale/article/details/89350095