Java String.intern()_学习笔记

参考:https://www.jianshu.com/p/0d1c003d2ff5java

String.intern()

String.intern()是native方法,底层调用c++中的StringTable:intern方法。c++

当调用intern方法是,若是常量池已经存在该字符串,则返回池中字符串。数组

不然将此字符串添加到常量池中,并返回字符串的引用。数据结构

package com.ctrip.ttd.whywhy;
class Test {
    public static void main(String args[]) {
        String s1 = new StringBuilder().append("String").append("Test").toString();
        System.out.println(s1.intern() == s1);

        String s2 = new StringBuilder().append("ja").append("va").toString();
        System.out.println(s2.intern() == s2);
    }
}

在 JDK6 和 JDK7 中结果不同:app

一、JDK6的执行结果:false false
对于这个结果很好理解。在JDK6中,常量池在永久代分配内存,永久代和Java堆的内存是物理隔离的,执行intern方法时,若是常量池不存在该字符串,虚拟机会在常量池中复制该字符串,并返回引用,因此须要谨慎使用intern方法,避免常量池中字符串过多,致使性能变慢,甚至发生PermGen内存溢出。性能

 
 

二、JDK7的执行结果:true false
对于这个结果就有点懵了。在JDK7中,常量池已经在Java堆上分配内存,执行intern方法时,若是常量池已经存在该字符串,则直接返回字符串引用,不然复制该字符串对象的引用到常量池中并返回,因此在JDK7中,能够从新考虑使用intern方法,减小String对象所占的内存空间。测试

 
 

对于变量s1,常量池中没有 "StringTest" 字符串,s1.intern() 和 s1都是指向Java对象上的String对象。
对于变量s2,常量池中一开始就已经存在 "java" 字符串,因此 s2.intern() 返回常量池中 "java" 字符串的引用。优化

String.intern()性能

常量池底层使用StringTable数据结构保存字符串引用,实现和HashMap相似,根据字符串的hashcode定位到对应的数组,遍历链表查找字符串,当字符串比较多时,会下降查询效率。ui

在JDK6中,因为常量池在PermGen中,受到内存大小的限制,不建议使用该方法。spa

public class StringTest {
    public static void main(String[] args) {
        System.out.println(cost(1000000));
    }

    public static long cost(int num) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < num; i++) {
            String.valueOf(i).intern();
        }
        return System.currentTimeMillis() - start;
    }
}

执行一百万次intern()方法,不一样StringTableSize的耗时状况以下:
一、-XX:StringTableSize=1009, 平均耗时23000ms;
二、-XX:StringTableSize=10009, 平均耗时2200ms;
三、-XX:StringTableSize=100009, 平均耗时200ms;
四、默认状况下,平均耗时400ms;

在默认StringTableSize下,执行不一样次intern()方法的耗时状况以下:
一、一万次,平均耗时5ms;
二、十万次,平均耗时25ms;
三、五十万次,平均耗时130ms;
四、一百万次,平均耗时400ms;
五、五百万次,平均耗时5000ms;
六、一千万次,平均耗时15000ms;

从这些测试数据能够看出,尽管在Java 7以上对intern()作了细致的优化,但其耗时仍然很显著,若是无限制的使用intern()方法,将致使系统性能降低,不过能够将有限值的字符串放入常量池,提升内存利用率,因此intern()方法是一把双刃剑。

相关文章
相关标签/搜索