JVM - StringTable

 
StringTable:在方法区中的运行常量池中,会将第一次定义的String存入其中,下次再出现时直接将变量指向里面的值。结构是hash表
 
        String s1 = "ha";
        String s2 = "ha";
        String s3 = s1 +s2;
        String s4 = "ha" + "ha";
        String s5 = "haha";
        String s6 = new String("haha");
        System.out.println(s3 == s4);
        System.out.println(s4 == s5);
        System.out.println(s5 == s6);

输出:

false

true

false

s3本质调用了 new StringBuilder.append("a").append("b").toString(); 声明了新的引用变量,开辟了新的空间,所以指向的是堆中的对象地址而不是StringTable中的字符串了。

s6同理

s4 = "ha" + "ha";因为是两个常量拼接,在编译时就会直接变成"haha"进行处理,进入StringTable

s5 = "haha",因为也是常量,会先在StringTable中查找,找到后s5指向了StringTable中的"haha",因此s4 == s5返回true。

 

String.intern()方法,如果String在StringTable中不存在,则可以将这个String加入StringTable中,并返回这个对象。

比如上面的方法中加入s3.intern(),

        String s1 = "ha";
        String s2 = "ha";
        String s3 = s1 +s2;
        s3.intern();
        String s4 = "ha" + "ha";
        System.out.println(s3 == s4);

输出:

true

因为s3的值"haha"被放入了StringTable,s3指向了StringTable的"haha"对象

 

把haha变为main

        String s1 = "ma";
        String s2 = "in";
        String s3 = s1 +s2;
        s3.intern();
        String s4 = "ma" + "in";
        System.out.println(s3 == s4);

输出:

main String,java等属于关键词,在一开始就在StringTable中存在了,所以s3.intern没能插入进去。

 

改回haha,如果再在s3前加入一个String ss = "haha";

        String s1 = "ha";
        String s2 = "ha";
        String ss = "haha";
        String s3 = s1 +s2;
        s3.intern();
        String s4 = "ha" + "ha";
        System.out.println(s3 == s4);

输出:

false

因为s3.intern()执行时发现StringTable中有了"haha"了,所以没能加入成功,s3依旧是指向了堆内存中的对象。

 

-Xms500m  设置堆内存为500mb

-XX:StringTableSize=2000  将StringTable中的桶个数设为2000。 hash表桶的数量越多(数组部分长度越长),数据越分散,hashcode撞车的概率越小,速度越快。 默认值是6万多

-XX:+PrintStringTableStatistics 显示StringTable的状况。

 

StringTable有内存回收机制

打开“Run->Edit Configurations”菜单

 

 在VM option(虚拟机设置)中,加入代码:-XX:StringTableSize=2000 ,点击ok,然后运行下面的代码

        long t1 = new Date().getTime();
        String[] a = new String[1000000];
        for(int i=0; i<1000000; i++){
            a[i] = ("" + i).intern();
        }
        long t2 = new Date().getTime();
        System.out.println(t2 - t1);

运行时间为9000多毫秒。

 

然后修改VM option:-XX:StringTableSize=20000,点击ok,然后再尝试

运行时间为1000多毫秒

 

然后修改VM option:-XX:StringTableSize=200000,点击ok,然后再尝试

运行时间为400多毫秒

posted @ 2019-10-28 11:37  不咬人的兔子  阅读(805)  评论(0编辑  收藏  举报