JVM-StringTable
作者:互联网
String的基本特性
- String 字符串
- String s1 = "vic"; //字面量的定义方式
- String s2 = new String("vic");
- String 声明为final,不可被继承
- 实现了Serializable、Comparable,可序列化、可排序
JDK8及以前内部定义了final char[] values 存储字符串数据,JDK9之后改为byte[]
根据JDK官方描述:大部分内容都是拉丁文所以一个byte就能存储,所以改为byte[]+编码的方式节省空间
StringBuffer、StringBuild都同样的做了修改
不可变字符序列
- 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原来的value进行赋值
- 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值
- 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原来的value赋值
通过字面量的方式给一个字符串赋值,此时的字符串值声明在字符串常量池中
字符串常量池中不会存在相同内容的字符串
String.intern() 如果字符串常量池中没有对应data字符串的话,则在常量池中生成,并反回在字符串常量池中地址
- String的String Pool是一个固定大小的HashTable,JKD6及之前默认长度为1009,JDK7后默认长度调整为60013
- 因为如果String Pool中放入过多的String,会造成比较多的Hash冲突,而导致链表长度变长,而链表长度变长后直接导致了String.intern性能下降
- -XX:StringTableSize 可设置StringTable长度
- JDK8时StringTableSize最小值1009
String的内存分配
String类型的常量池比较特殊,主要使用方式有两种:
- 只用使用双引号声明出来的String对象会直接存储在常量池中。比如:String s = "String";
- 如果不是用双引号声明的String对象,可以使用String提供的intern()方法
Java6及以前,字符串常量池存在永久代
Java7,字符串常量池的位置调整到Java堆内
Java8,字符串常量在堆内
为什么StringTable要调整?
- permSize默认比较小
- 永久代垃圾回收的频率很低
String基本操作
public static void main(String[] args) {
System.out.println();
System.out.println("1");
System.out.println("2");
// 字符串"1"、"2"不会被再次加载
System.out.println("1");
System.out.println("2");
}
class Memory {
public static void main(String[] args){
int i = 1;
Object obj = new Object();
Memory mem = new Memory();
mem.foo(obj);
}
private void foo(Object param) {
String str = param.toString();
System.out.println(str);
}
}
字符串拼接操作
- 常量和常量的拼接结果在常量池,原理是编译期优化
- 只要其中一个是变量,结果就在堆中,变量拼接的原理是StringBuilder
- 如果拼接结果调用intern() 方法,则主动将常量池还没有的字符串对象放入池中,并返回次对象地址
public void test1() {
String s1 = "a" + "b" + "c";
String s2 = "abc";
/*
* 常量和常量的拼接结果在常量池
*/
System.out.println(s1 == s2); // true
System.out.println(s1.equal(s2)); // true
}
public void test2() {
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
/*
* 只要其中一个是变量,则相当于在堆空间中new String(), 具体内容为拼接的结果:javaEEhadoop
*/
System.out.println(s3 == s4); // true
System.out.println(s3 == s5); // false
System.out.println(s3 == s6); // false
System.out.println(s3 == s7); // false
System.out.println(s5 == s6); // false
System.out.println(s5 == s7); // false
System.out.println(s6 == s7); // false
String s8 = s6.intern();
System.out.println(s3 == s8); // true
}
public void test3() {
String s1 = "a";
String s2 = "b";
String s3 = "ab";
/*
* s1 + s2的执行细节:
* 1. StringBuilder s = new StringBuilder();
* 2. s.append("a");
* 3. s.append("b");
* 4. s.toString(); -> 约等于new String("ab");
*/
String s4 = s1 + s2;
System.out.println(s3 == s4); // false
}
标签:String,常量,StringTable,System,字符串,JVM,println,out 来源: https://www.cnblogs.com/baojiong/p/15317969.html