1 运行时常量池
常量池,就是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等信息
运行时常量池,常量池是 *.class 文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址
2 StringTable(串池)
先看一道面试题:
String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();
// 问
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);
String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();
// 问,如果调换了【最后两行代码】的位置呢,如果是jdk1.6呢
System.out.println(x1 == x2);
答案是:false true true false(调换后true)
上面程序使用javap -v反编译后得到JVM指令如下:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=9, args_size=1
0: ldc #2 // String a
2: astore_1
3: ldc #3 // String b
5: astore_2
6: ldc #4 // String ab
8: astore_3
9: new #5 // class java/lang/StringBuilder
12: dup
13: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
16: aload_1
17: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
20: aload_2
21: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: astore 4
29: ldc #4 // String ab
31: astore 5
33: aload 4
35: invokevirtual #9 // Method java/lang/String.intern:()Ljava/lang/String;
38: astore 6
40: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
43: aload_3
44: aload 4
46: if_acmpne 53
49: iconst_1
50: goto 54
53: iconst_0
54: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V
57: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
60: aload_3
61: aload 5
63: if_acmpne 70
66: iconst_1
67: goto 71
70: iconst_0
71: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V
74: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
77: aload_3
78: aload 6
80: if_acmpne 87
83: iconst_1
84: goto 88
87: iconst_0
88: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V
91: new #5 // class java/lang/StringBuilder
94: dup
95: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
98: new #12 // class java/lang/String
101: dup
102: ldc #13 // String c
104: invokespecial #14 // Method java/lang/String."<init>":(Ljava/lang/String;)V
107: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
110: new #12 // class java/lang/String
113: dup
114: ldc #15 // String d
116: invokespecial #14 // Method java/lang/String."<init>":(Ljava/lang/String;)V
119: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
122: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
125: astore 7
127: ldc #16 // String cd
129: astore 8
131: aload 7
133: invokevirtual #9 // Method java/lang/String.intern:()Ljava/lang/String;
136: pop
137: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
140: aload 8
142: aload 7
144: if_acmpne 151
147: iconst_1
148: goto 152
151: iconst_0
152: invokevirtual #11 // Method java/io/PrintStream.println:(Z)V
155: return
分析:
s1引用的是串池中的常量”a”
s2引用的是串池中的常量”b”
s3引用的是编译时优化的”a”“b”拼接后的串池中的常量”ab”
s4引用的是堆中StringBuilder对象调用init方法初始化,并append”a”,又append”b”,最后调用toString得到的String对象
s5引用的是串池中的常量”ab”
s6,由于s4的对象内容”ab”在s3执行时就已经入池,因此返回串池中的”ab”,即s3的地址
x2引用的是堆中StringBuilder对象调用init方法初始化,并append堆中创建的”c”和”d”String对象,最后调用toString得到的String对象
x1引用的是串池中的常量”cd”
x2.intern();执行完上一句后,此时串池中已有”cd”,不会将x2放入串池,x2仍引用堆中的对象地址
注意1:若执行x2.intern();后再String x1 = “cd”;则两个变量引用的都是串池中的”cd”的地址
注意2:以上都是jdk1.8版本的答案,如果是jdk1.6,在String x2 = new String(“c”) + new String(“d”);后,先执行x2.intern();再String x1 = “cd”;分析为:x2.intern()将堆中对象拷贝到串池中,导致x1==x2结果为false
intern方法说明:
功能:将串池中还没有的字符串对象放入串池
1.8 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池, 会把串池中的对象返回
1.6 将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回
StringTable总结
位置 | GC | 调优 |
---|---|---|
1.8版本位于堆中 1.6版本只存在于老年代 |
1.8时触发minorGC 1.6时触发fullGC |
增大堆内存的同时 适当增加StringTableSize桶个数可以减少寻址时的hash碰撞概率,从而节省读写时间 intern方法使对象入池复用(大量重复情况),可以节省大量创建新对象占用堆内存 |
原文地址:https://blog.csdn.net/jason_bone_/article/details/135514961
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_54542.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!