String Table

概述

  1. String是final类
  2. String实现了Serializable、Comparable < String >、CharSequence接口
  3. 在jdk9以前使用char数组储存字符串数据,jdk8以后使用byte数组
 @Stable
    private final byte[] value;
  1. String 对象是不可变的
  2. 通过字面量的方式(String str = "str")给一个字符串赋值,字符串值声明在字符串常量池中
  3. 字符串常量池不会储存相同内容的字符串
  4. String的String Pool是一个固定大小的HashTable,在String Pool中存放的String过多会造成Hash冲突严重,从而导致链表很长,继而导致调用String.intern时性能会大幅下降
  5. 可以使用参数 -XX:StringTableSize 设置StringTable的长度,jdk8中StringTable最小值为1009,jdk11中StringTable最小值为128,最大值为16777216

String的内存分配

  1. 直接使用双引号声明的String会存放在字符串常量池中
  2. 使用String类的intern()方法
  3. jdk7以前字符串常量池存放在永久代中
  4. jdk7中字符串常量池存放在堆中

字符串拼接

  1. 常量与常量的拼接结果在常量池,因为编译期优化
  public void hello() {
    String str1 = "a" + "b";
    String str2 = "ab";
    System.out.println(str1 == str2);
  }


2. 常量池中不会存放相同内容的常量
3. 只要其中有一个是变量,结果就在堆中,使用了StringBuilder

 public void hello() {
    String str1 = "a" + "b";
    String str2 = "a";
    String str3 = str2 + "b";
  }


4. 如果拼接的结果调用String类的intern()方法,将常量池中还没有的字符串对象放入池中,并返回对象地址

intern()

  1. 当调用 intern 方法时,如果池中已经包含String由equals(Object)方法确定的等于此对象的字符串,则返回池中的字符串。否则,将此String对象添加到池中并String返回对此对象的引用。
  2. 如果不是双引号声明的String对象,可以使用String类的intern()方法
  3. new String("abc")会创建几个对象?
    两个
  4. newString("a") + new String("b")会创建几个对象?
    对象1:new String("a")、对象2:常量池中的"a"、对象3:new String("b")、对象4:常量池中的"b"、对象5:new StringBuilder()、对象6:StringBuilder.toString()方法的new String()
  5. new String()返回的是堆空间的对象
  6. jdk1.6中调用intern方法,将这个字符串对象尝试放入字符串常量池
    6.1 如果字符串常量池里有,返回这个对象在字符串常量池的地址
    6.2 如果没有,把这个对象复制一份,放入到字符串常量池中,返回字符串常量池中的对象地址
  7. 从jdk1.7开始,调用intern方法,将这个字符串对象尝试放入字符串常量池
    7.1 如果字符串常量池里有,返回这个对象在字符串常量池的地址
    7.2 如果没有,把对象的引用地址复制一份并放入字符串常量池中,返回字符串常量池中的引用地址
  8. 对于存在着大量重复的字符串的程序,可以使用intern()节省空间

StringTable的垃圾回收

  1. 在G1垃圾收集器中实现自动持续对重复的String对象进行去重
  2. 当垃圾收集器工作的时候,会访问堆上存活的对象。对每一个访问的对象都会检查是否是候选的要去重的string对象
  3. 如果是,把这个对象的一个引用插入到队列中等待后续的处理。一个去重的线程在后台运行,处理这个队列。处理队列的一个元素意味着从队列删除这个元素,然后尝试去重它引用的string对象
  4. 使用一个hashtable来记录所有的被string对象使用的不重复的char数组。当去重的时候,会查这个hashtable,来看堆上是否已经存在一个一模一样的char数组
  5. 如果存在,String对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉
  6. 如果查找失败,char数组会被插入到hashtable,这样以后的时候就可以共享这个数组
  7. -XX:+UseStringDeduplication:开启String去重,默认不开启(jdk11—)
  8. -Xlog:stringdedup*=debug:打印详细的去重统计信息(jdk11)
  9. -XX:StringDeduplicationAgeThreshold=?:到达这个年龄的String对象被认为是去重的候选对象
posted @ 2021-12-09 16:44  翻蹄亮掌一皮鞋  阅读(144)  评论(0)    收藏  举报