30.jvm内存结构部分——StringTable编译期优化

package design.wlb.studyjava.demo.restudy.c4jvm专题.chapter02.c30StringTable编译期优化;

public class Client {
	//我们通过new关键字创建的堆对象,都会使用堆的内存。
	//jdk1.6中,StringTable串池在常量池在方法区中,jdk1.8中,常量池在元空间不归jvm管理,但串池不在常量池中,是在堆中。

	//StringTable["a","b","ab"](懒加载)
	public static void main(String[] args) {
		String s1 = "a";		//ldc #2 astore_1 从常量池加载为java字符串常量对象,将这个对象放入串池中,并存储到局部变量表的1号位置。
		String s2 = "b";
		String s3 = "ab";
		String s4 = s1 + s2;
		String s5 = "a"+"b";	//javac编译器优化,在编译时,直接认为此为固定的常量 "ab" ,故而反编译后的指令为ldc #4 astore 5 存入到第五个局部变量表中
		System.out.println(s5==s3);

		//s4在非串池的其他堆中,s5在串池中。
	}

	/**
	 *   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: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
	 *  36: aload         5
	 *  38: aload_3
	 *  39: if_acmpne     46
	 *  42: iconst_1
	 *  43: goto          47
	 *  46: iconst_0
	 *  47: invokevirtual #10                 // Method java/io/PrintStream.println:(Z)V
	 *  50: return
	 */
}

由我们的javap反编译工具可知,

String s5 = "a"+"b";

在jvm指令对应的是"ldc #4", 以及astore 5


它和我们想象的有点区别,它并不是使用的StringBuilder进行字符串拼接了,因为此处"a"+"b",两者都是字符串常量,在javac编译期,jdk就认识它只会是"ab".故而,进行了java编译期优化,在生成的class文件后,就已经变成了String s5 = "ab";

所以它的加载方式也和s3一模一样。ldc #4 astore 5,从运行时常量池中取出"ab",然后存入局部变量表的5号位置【astore aload 是一对操作局部变量表的jvm指令】


也就是说,jvm从运行期常量池查表#4的位置获取将其变为java对象"ab",再将java字符串常量对象"ab"放入串池(另一个堆区),但放入串池中的时候会去查串池中的key 有不有,此时因为有了String s3 = "ab",串池中已经有了"ab",所以jvm直接从串池中查表找到了它。

所以s3和s5都是从串池中获取值,故而s3 == s5 答案是false;


补充:

1.串池也叫字符串常量池

2.串池可以理解为逻辑上在运行期常量池里面(jdk1.6在永久代里面,物理上也是在运行常量池中,jdk1.8运行期常量池在元空间里面,但串池逻辑上在,但物理上是存在jvm的堆中)

好,这一篇就讲到这里。

上一篇:29.jvm内存结构部分——StringTable_字符串变量的拼接_tgbyhn31的博客-CSDN博客

下一篇:31.jvm内存结构部分——StringTable字符串延迟加载_tgbyhn31的博客-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值