前言方法区(MethodArea)是线程共享的内存区域,包括JVM加载的类型信息、常量、静态变量、JVM编译后的代码缓存都存放在方法区。运行时常量池(RuntimeConstantPool)是方法区的一部分。Class文件中的一部分内容是常量池表(ConstantPoolTable),用于存放编译过程中产生的各种字面量和符号引用。这部分内容Class文件加载到JVM后,会存放在运行时常量池中。字符串文字存储在字符串常量池中。在JDK1.8中,字符串常量池存在于堆中。本文将讲解JDK1.8中的方法区、运行时常量池和字符串常量池的区域分布,重点分析字符串常量池,探讨一个新的字符串对象是否会在堆上创建几个对象。JDK版本:1.8参考资料:《深入理解Java虚拟机第三版》正文1.方法区的区域分布方法区只是一个逻辑概念。在JDK1.8中,方法区的具体实现是元空间,元空间使用本地内存。在JDK1.8中,方法区、运行时常量池和字符串常量池的区域分布图如下图所示。即字符串常量池存在于堆中,如果要设置方法区的大小,需要使用-XX:MaxMetaspaceSize=命令设置。在JDK1.8中,使用元空间作为方法区的实现来替代永久代(PermGen),原因如下。当永久代作为方法区的实现时,字符串常量池存在于运行时常量池中,即字符串常量池存在于方法区中,方法区只有在被清理时才会被清理FullGC,所以很容易出现由于string常量池导致的内存溢出;类型信息等数据的大小不易确定,存放在本地内存中比较合适。2、字符串常量池首先回答了经典问题:一个新的字符串对象会创建若干个对象。答案是一两个。字符串字面量存储在字符串常量池中,字符串字面量本质上是对象。当代码中出现如下代码时。Stringstr="樱花";如果字符串常量池中已经存在字符串字面量sakura,那么str会指向字符串常量池中的sakura字符串字面量,否则,会先将字符串字面量sakura添加到字符串常量池中,然后再将str指向字符串常量池中的sakura字符串字面量。更进一步,其实代码中只要出现一个双引号括起来的字符串,就会去字符串常量池中寻找对应的字符串字面量。如果找不到,则创建一个字符串字面量,并将其添加到常量池中的字符串中。现在如果代码中出现如下代码。Stringstr=newString("樱花");首先出现了用双引号括起来的sakura字符串,于是会去字符串常量池中寻找对应的字符串字面量,如果没有找到,就创建一个sakura字符串,将字面量值加入到字符串常量池中。如果找到,则直接使用字符串常量池中的sakura字符串字面量值。最后会在堆上创建一个字符串对象,str指向堆上创建的字符串对象。所以new一个字符串对象的时候,肯定会在堆上创建一个字符串对象,但是是否会在字符串常量池中创建一个字符串字面量,就看这个字符串字面量之前是否已经存在了。如果已经存在,则不会再次创建。因此,new一个字符串对象将创建多个对象的答案是一个或两个。为了更好地理解,请考虑以下示例。publicclassStringTest{publicstaticvoidmain(String[]args){Stringstr1=newString("sakura")+newString("sakura");//第一步Stringstr2="sakurasakura";//第二步系统.out.println(str1==str2);//Step3}}step1执行完后,堆上的情况如下。步骤2执行完后,堆上的情况如下。所以第3步最后的打印结果一定是false。3.String的intern()方法首先考虑下面的例子。publicclassStringTest{publicstaticvoidmain(String[]args){Stringstr1=newString("sakura")+newString("sakura");//步骤1str1.intern();//第二步Stringstr2="sakurasakura";//第三步System.out.println(str1==str2);//Step4}}上面的例子与第2节的例子类似,只是多了一个str1.intern()的步骤。String的intern()方法会根据当前字符串对象的值在字符串常量池中进行匹配。如果字符串常量池中字符串字面量的值等于当前字符串对象的值,则返回该字符串字面量的地址,如果字符串常量池中不存在其值等于的字符串字面量当前字符串对象的值,在字符串常量池中注册一个引用并指向当前字符串对象,最后返回当前字符字符串对象的地址。那么在上面的例子中,执行完第2步之后,堆上的情况如下。步骤3执行完后,堆上的情况如下。所以第4步最后的打印结果一定是真的。从上面的例子我们可以知道,字符串常量池除了存储字符串字面量外,还存储了堆上字符串对象的引用。总结方法区用于存放JVM加载的类型信息、常量、静态变量、即时编译器编译的代码缓存等数据。在JDK1.8中,元空间作为方法区的实现,元空间使用本地内存。字符串文字存储在字符串常量池中。字符串文字本质上是对象。当创建一个新的字符串对象时,会在堆上创建一个字符串对象,但是会在字符串常量池中创建一个字符吗?字符串字面量取决于这个字符串字面量之前是否已经存在,如果已经存在就不会再创建,所以一个新的字符串对象会创建多少个对象,答案是一个还是两个。
