01-006 jvm StringTable

常量池与串池关系

举例:(老师这里讲的特别特别特别好!!)

// StringTable [ "a", "b" ,"ab" ]  hashtable 结构,不能扩容
public class Demo {
    // 常量池中的信息,都会被加载到运行时常量池中, 这时 a b ab 都是常量池中的符号,还没有变为 java 字符串对象
    // ldc #2 会把 a 符号变为 "a" 字符串对象
    // ldc #3 会把 b 符号变为 "b" 字符串对象
    // ldc #4 会把 ab 符号变为 "ab" 字符串对象

    public static void main(String[] args) {
        String s1 = "a"; // 懒惰的
        String s2 = "b";
        String s3 = "ab";
        String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString()  new String("ab")
         System.out.println(s3 == s5);//false
        String s5 = "a" + "b";  // javac 在编译期间的优化,结果已经在编译期确定为ab
        System.out.println(s3 == s5);//true
    }
}

StringTable的特性

1.常量池中的字符串仅为符号,第一次用到时才会变为对象,字符串延迟加载;
2.利用串池的机制,避免重复创建字符串对象;
3.字符串常量拼接的原理是编译期优化;
4.字符串变量拼接的原理是StringBuilder(1.8);
5.intern()可将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回。
下面的情况基于JDK1.8,intern()1.8不会拷贝

public class Demo1 {

    //  ["ab", "a", "b"]
    public static void main(String[] args) {
        String s = new String("a") + new String("b");
        
        // 堆  new String("a")   new String("b") new String("ab")
        String s2 = s.intern(); // 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
       
        System.out.println( s2 == s); //true
        System.out.println( s == "ab"); //true
    }

}
public class Demo2 {

    //  ["ab", "a", "b"]
    public static void main(String[] args) {
        String x = "ab";
        String s = new String("a") + new String("b");

        // 堆  new String("a")   new String("b") new String("ab")
        String s2 = s.intern(); // 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回

        System.out.println( s2 == x);  //true
        System.out.println( s == x ); //false
    }

}

字符串相关面试题

public class Test {

    public static void main(String[] args) {
        String s1 = "a";
        String s2 = "b";
        String s3 = "a" + "b"; // ab
        String s4 = s1 + s2;   // new String("ab")
        String s5 = "ab";
        String s6 = s4.intern();

// 问
        System.out.println(s3 == s4); // false
        System.out.println(s3 == s5); // true
        System.out.println(s3 == s6); // true

        String x2 = new String("c") + new String("d"); // new String("cd")
        x2.intern();
        String x1 = "cd";

// 问,如果调换了【最后两行代码】的位置呢,如果是jdk1.6呢 false/true
        System.out.println(x1 == x2); //true
    }
}

StringTable的位置

1.6 时在永久代的常量池中,永久代回收效率不高要到,垃圾回收触发的很晚(老年代);
1.7、1.8转移到堆中,垃圾回收的早;
实验报错情况

/**
 * 演示 StringTable 位置
 * 在jdk8下设置 -Xmx10m -XX:-UseGCOverheadLimit
 * 在jdk6下设置 -XX:MaxPermSize=10m
 */
public class Demo68 {

    public static void main(String[] args) throws InterruptedException {
        List<String> list = new ArrayList<String>();
        int i = 0;
        try {
            for (int j = 0; j < 260000; j++) {
                list.add(String.valueOf(j).intern());
                i++;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            System.out.println(i);
        }
    }
}

GC overhead limit exceeded:98%的时间垃圾回收只达到2%的回收时报错。

StringTable垃圾回收

/**
 * 演示 StringTable 垃圾回收
 * -Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc(打印垃圾回收详细信息)
 */
public class DemoGC {
    public static void main(String[] args) throws InterruptedException {
        int i = 0;
        try {
            for (int j = 0; j < 100000; j++) { // j=100, j=10000
                String.valueOf(j).intern();
                i++;
            }
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            System.out.println(i);
        }
    }
}

StringTable性能调优

1.-XX:StringTableSize=桶个数,设置合适的参数,虽然参数较大会消耗一点内存;
参数太小会引起hash碰撞,查找字符串时比较消耗CPU,1.6起参数过小会自动rehash,但rehash前后bucket数量不变,不断的rehash也会消耗CPU,所以应当设置大小合理的参数。
2.考虑字符串对象是否入池,入池可以节约堆内存;

学习整理于解密JVM.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值