JVM——String Table字符串常量池
String table又称为String pool,字符串常量池,其存在于堆中(jdk1.7之后改的)。最重要的一点,String table中存储的并不是String类型的对象,存储的而是指向String对象的索引,真实对象还是存储在堆中。
先看几道经典面试题:
String s1 = "a"; //在常量池中
String s2 = "b"; //在常量池中
String s3 = "a" + "b"; //在常量池中
String s4 = s1 + s2; //字符串变量拼接的原理是 StringBuilder (jdk1.8)(相当于在堆中新建了一个对象)
String s5 = "ab"; //在常量池中直接查找"ab".字符串常量拼接的原理是编译期优化
String s6 = s4.intern(); // intern 方法,主动将串池中还没有的字符串对象放入串池。
// 问
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);
String x2 = new String("c") + new String("d"); //在堆中创建" c", "d" ,"cd"
String x1 = "cd"; //在串池中创建"cd".
x2.intern(); //主动将串池中还没有的字符串对象放入串池,如果有则并不会放入,如果没有则放入串池。两种情况都会把串池中的对象返回。
// 问,
System.out.println(x1 == x2);
如果调换了【最后两行代码】的位置呢
StringTable 特性
1.String Table 是哈希表结构,不能扩容。
2.常量池中的字符串仅是符号,第一次用到时才变为对象。
3.利用串池的机制,来避免重复创建字符串对象。
4.字符串变量拼接的原理是 StringBuilder (1.8)(相当于在堆中新建了一个对象)。
5.字符串常量拼接的原理是编译期优化。
6.可以使用 intern 方法,主动将串池中还没有的字符串对象放入串池。
7.jdk1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池。(原来堆中的就没有了)两种情况都会把串池中的对象返回。
8.jdk1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回。
输出的结果应该为:
false
true
ture
false
ture
把这个面试题读懂之后,基本上StringTable的基础问题都可以自己解决了。
StringTable的垃圾回收及调优
字符串存在于堆内存中,只有当内存紧张时,才会触发垃圾回收。
(1) 它的底层由于是哈希表,我们可以设置-XX:StringTableSize=桶个数,一般大小设置大一点,可以减少哈希冲突,使StringTable的性能提高。
(2)考虑将字符串是否入池。例如存储地址,那么有可能不同的用户有相同的地址,这时我们就要加以区分,所以采用字符串的 intern()方法,减少字符串对于内存的占用。