JVM专题-StringTable
Posted IT老刘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM专题-StringTable相关的知识,希望对你有一定的参考价值。
1.StringTable特性
-
常量池中的字符串仅是符号,第一次用到时才变成对象。
-
利用串池的机制,来避免重复创建字符串对象
-
字符串变量拼接的原理是
StringBuilder(1.8)
-
字符串常量拼接的原理是编译期优化
-
可以使用intern方法,主动将串池中还没有的字符串对象放入串池
-
1.8将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,两种情况均会把串池中的对象返回。
-
1.6将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池,两种情况均会把串池中的对象返回。即调用intern的对象,和将来放入串池的对象,是两个对象。
public class Demo1_23
// ["ab", "a", "b"]
public static void main(String[] args)
String x = "ab";
String s = new String("a") + new String("b");
// 堆 new String("a") new String("b") new String("ab")
String s2 = s.intern(); // 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
System.out.println( s2 == x);//true
System.out.println( s == x );//false
- 执行到第10行String s2 = s.intern(); 时,将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回。由于String x = “ab”;StringTable中有"ab"了,所以s不会放在常量池。但是会吧常量池的"ab"返回回来给s2。
所以 s2 == x 即 常量池的"ab" - s != x,因为s没有放进去
public class Demo1_223
// ["a", "b","ab" ]
public static void main(String[] args)
String s = new String("a") + new String("b");
// 堆 new String("a") new String("b") new String("ab")
String s2 = s.intern(); // 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
System.out.println( s2 == "ab"); //true
System.out.println( s == "ab" ); //true
- 执行到第10行String s2 = s.intern(); 时,将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回。此时StringTable还没有"ab",所以s会放在常量池。同时常量池的"ab"返回回来给s2。
所以 s2 == x 即 常量池的"ab" - s == x,因为s放进去了
JDK1.6运行情况:
public class Demo111
// ["a", "b","ab" ]
public static void main(String[] args)
String s = new String("a") + new String("b");
// 堆 new String("a") new String("b") new String("ab")
String s2 = s.intern(); // 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
System.out.println( s2 == "ab"); //true
System.out.println( s == "ab" ); //false
2.StringTable面试题
public class Demo1_21
public static void main(String[] args)
String s1 = "a";
String s2 = "b";
String s3 = "a"+"b"; // 优化为"ab"
String s4 = s1 + s2; // new StringBuilder 在堆中
String s5 = "ab"; // 去串池查找添加
String s6 = s4.intern();
System.out.println(s3 == s4); // false
System.out.println(s3 == s5); // true
System.out.println(s3 == s6); // true
String x2 = new String("c") + new String("d"); // new String("cd")
String x1 = "cd"; //"cd"
x2.intern(); // 串池已经有cd,x2放不进去
System.out.println(x1 == x2); // false
如果调换位置
String x2 = new String("c") + new String("d"); // new String("cd")
x2.intern(); // 串池已没有cd,x2放进去
String x1 = "cd"; //"cd"
System.out.println(x1 == x2); // true
3.StringTable位置
-
在1.6之前。StringTable在方法区永久代中,但是放在这之中,虚拟机只会在full GC时才会对StringTable进行垃圾回收。但是其实StringTable的操作是非常频繁的,如果没有即使进行垃圾回收,容易造成永久代空间不足。
-
在1.8后,StringTable放在了堆中,使其垃圾回收的效率更高。
4.案例
JDK1.6下
虚拟机参数
-XX:MaxPermSize=10m //永久代空间设置
package com.bruce.test;
import java.util.ArrayList;
import java.util.List;
/**
* 演示 StringTable 位置
* 在jdk8下设置 -Xmx10m -XX:-UseGCOverheadLimit
* 在jdk6下设置 -XX:MaxPermSize=10m
*/
public class Demo1_6
public static void main(String[] args) throws InterruptedException
List<String> list = new ArrayList<String>();
int i = 0;
try
for (int j = 0; j < 260000; j++)
list.add(String.valueOf(j).intern());
i++;
catch (Throwable e)
e.printStackTrace();
finally
System.out.println(i);
JDK1.8下
虚拟机参数
// 堆空间大小设置
-Xmx10m
public class Demo1_221
public static void main(String[] args)
List<String> list = new ArrayList<>();
int i = 0;
try
for (int j = 0; j < 260000; j++)
list.add(String.valueOf(j).intern());
i++;
catch (Throwable e)
e.printStackTrace();
finally
System.out.println(i);
添加JVM参数:
// 堆空间大小设置、关闭UseGCOverheadLimit
-Xmx10m -XX:-UseGCOverheadLimit
可以看到1.6是永久代空间溢出,1.8是堆空间溢出。
5.StringTable垃圾回收
StringTable中的字符串常量不再引用后,也会被垃圾回收。
package com.method.area;
/**
* 演示 StringTable 垃圾回收
* -Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc
*/
public class Demo1_231
public static void main(String[] args)
int i = 0;
try
for (int j = 0; j < 10; j++)
//String.valueOf(j).intern();
i++;
catch (Throwable e)
e.printStackTrace();
finally
System.out.println(i);
public class Demo1_23
public static void main(String[] args)
int i = 0;
try
for (int j = 0; j < 10; j++)
String.valueOf(j).intern();
i++;
catch (Throwable e)
e.printStackTrace();
finally
System.out.println(i);
for (int j = 0; j < 100000; j++)
String.valueOf(j).intern();
i++;
清理了一些未引用的字符串常量。
以上是关于JVM专题-StringTable的主要内容,如果未能解决你的问题,请参考以下文章