JVM字符串常量池

String

  • 声明为final
  • 实现了Serializable、Comparable(可序列化、比较大小)
  • 内部结构
    • JDK8:char[]
    • JDK9:byte[],节省资源,StringBuffer、StringBuilder也发生改变
  • 代表不可变序列,具有不可变性
  • 对字符串重新赋值,需要重新指定内存空间赋值,不使用原来的value进行赋值
  • 通过字面量给字符串进行赋值,字符串声明在字符串常量池中
  • String.intern方法可将字符串存放至字符串常量池

字符串常量池

  • 不会存储相同内容的字符串
  • 字符串常量池是Hashtable
  • JDK6,固定大小1009
  • JDK7,默认长度60013
  • JDK8,1009是StringTable可设置的最小值
  • JDK7后,字符串常量池的位置由永久代变为堆中(永久代容量小、永久代回收频率低,对String的使用等不友好)

字符串拼接

  • 常量和常量(字面量、final修饰的变量)拼接结果放在常量池,编译期优化
  • 只要其中一个是变量,会使用StringBuilder的append方法,最后toString使用String构造器
  • 拼接的结果调用了intern方法,主动将常量池没有的字符串对象放入池中,并返回对象地址

intern

  • intern方法会从字符串常量池中查找当前字符串是否存在,若不存在,就将字符串放入常量池
  • intern方法返回结果所指向的类实例与以常量形式出现的字符串实例完全相同

intern版本比较

  • jdk6:如果字符串常量池没有字符串,就将对象复制一份放入字符串常量池
  • jdk7起:如果字符串常量池没有字符串,就将对象的引用地址复制一份放入字符串常量池
public class InternTest {
    @Test
    public void test1() {
        String s1 = new String("011");
        s1.intern();
        String s2 = "011";

        //jdk6、7、8:false
        System.out.println(s1 == s2);

        String s3 = new String("0") + new String("1");
        s3.intern();
        String s4 = "01";


        /*
         * jdk6:false,在字符串常量池创建新的对象
         * jdk7、8:true,字符串常量池引用了s3,s4引用字符串常量池的对象
         */
        System.out.println(s3 == s4);
    }

    @Test
    public void test2() {
        String s1 = new String("01") + new String("1");
        String s2 = s1.intern();

        /*
         * jdk6:false,字符串常量池的对象是新创建的
         * jdk7、8:true,s2引用字符串常量池的对象
         */
        System.out.println(s1 == "011");

        //jdk6、7、8:true,s2引用字符串常量池的对象
        System.out.println(s2 == "011");
    }
}

String去重

  • 堆存活数据集合里面String对象占25%
  • 堆存活集合重复的String对象由13.5%
  • String平均长度为45
  • G1垃圾收集器实现自动持续对重复的String对象去重,避免浪费内存

G1去重实现

  1. 访问堆中的对象,检查是否是候选的去重对象
  2. 如果是,把对象的引用插入到队列等待后续结果,一个去重的线程在后台运行处理队列,处理它意味着重队列删除元素,然后尝试去重它引用的String对象
  3. 使用StringTable记录所有被String对象使用的不重复char数组,当去重的时候,会查这个hashtable,看堆上是否有完全一样的char数组(jdk8以前String底层实现是char)
  4. 如果存在,String对象会调整引用那个数组,释放堆原来数组的引用,最终会被垃圾收集器回收
  5. 查找失败,就将char数组存放到Stringtable,以后可以共享此数组
参数
  • 开启去重:UseStringDuplicationStatistics(bool)
  • 打印去重信息:PrintStringDuplicationStatistics(bool)
  • 设置候选年龄:StringDuplicationAgeThreshold(uintx)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值