又拿出这道String str1 = new String("abc");创建几个对象的面试题梳理了一下常量池与方法区的关系,希望能把这两者的关系通过这道面试题说明白

方法区是什么

简单说方法区用于存储jvm加载的类的信息、常量、静态变量、编译后的代码

方法区、永久代与元空间的关系

下文都以HotSpot来说明

首先方法区是JVM规范的说法,永久代、元空间是HotSpot用来实现方法区的两个具体的实现

JDK1.8以前使用永久代Perm实现了JVM规范中的方法区

JDK1.8废弃永久代,变更为元空间,不是废弃了方法区

永久代与元空间的区别是元空间不在虚拟机内存中,而使用本地内存,目的是为了融合HotSpot与JRockit VM而做出的努力并且减少,并且由于这部分空间的GC效果难以令人满意

上面我们就说清楚了方法区、永久代与元空间这几个名词之间的关系和区别,下面我们在来看三个常量池的关系和不同

常量池

字符串常量池

是一个哈希表(StringTable),里面存的是驻留字符串的引用

字符串驻留:JVM 为了提高性能会将能在编译时期确定的字符串放在字符串驻留池的内存块中,String a = "abc"; String b = new String("def");都在编译时期能确定主流字符串"abc""def"

在堆中的字符串实例被这个哈希表引用之后就等同被赋予了”驻留字符串”的身份
在JVM中字符串常量池被所有类共享
字符串常量池在JDK1.7的版本从永久代移动到了堆

class文件常量池

class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。注意这是class文件中的内容
字面量就是我们所说的常量概念,如文本字符串、被声明为final的常量值等
符号引用是一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,通常包含:类的全限定名、字段的名称和描述符、方法的名称和描述符
总之这些内容能表示这个类的代码内容

运行时常量池

JDK1.7仅仅把字符串常量池移动到了堆,JDK1.8虽然废弃了永久代变更为元空间,但是运行时常量池仍然跟随元空间被移出JVM内存
当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个
并且在类加载的解析阶段会把运行时常量池的符号引用替换成直接引用,这个过程需要查找字符串常量池

由上面的内容我们可知new String对象创建问题只和堆以及堆内的字符串常量池有关系(字符串常量池在不在堆对new String没什么影响)

      //在堆中会有一个”abc”实例,全局StringTable中存放着”abc”的一个引用值
String str1 = "abc";
//生成两个实例,一个是”def”的实例对象,并且StringTable中存储一个”def”的引用值,还有一个是new出来的一个”def”的实例对象(指向str2)
String str2 = new String("def");
//查找StringTable,里面有”abc”的全局驻留字符串引用,所以str3的引用地址与之前的那个已存在的相同
String str3 = "abc";
//调用intern()函数,返回StringTable中”def”的引用值,如果没有就将str2的引用值添加进去
String str4 = str2.intern();
//最后str5在解析的时候就也是指向存在于StringTable中的”def”的引用值
String str5 = "def";
//生成一个实例,new出来的一个”def”的实例对象(指向str6),(def母本与StringTable放入”def”引用值已经创建)
String str6 = new String("def"); System.out.println(str1 == str3);//true System.out.println(str2 == str4);//false
System.out.println(str4 == str5);//true System.out.println(str5 == str2);//false
System.out.println(str6 == str2);//false System.out.println(str6 == str2.intern());//false
System.out.println(str6.intern() == str2.intern());//true

常量池与方法区以及又读new String对象创建问题的更多相关文章

  1. JDK方法区、元空间区别 & String.intern相关面试题

    一.方法区.永久代.元空间 1.方法区.永久代 方法区也是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息.常量.静态变量.即时编译器编译后的代码等数据.方法区域又被称为"永久代& ...

  2. jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解

    一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机:  1 ...

  3. 类的加载,链接和初始化——1运行时常量池(来自于java虚拟机规范英文版本+本人的翻译和理解)

    加载(loading):通过一个特定的名字,找到类或接口的二进制表示,并通过这个二进制表示创建一个类或接口的过程. 链接:是获取类或接口并把它结合到JVM的运行时状态中,以让类或接口可以被执行 初始化 ...

  4. Java方法区和运行时常量池溢出问题分析

    运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池 ...

  5. Java方法区和运行时常量池溢出问题分析(转)

    运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池 ...

  6. 对于JVM中方法区,永久代,元空间以及字符串常量池的迁移和string.intern方法

    在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法信息(如字节码,栈和变量大小),运行时常量池,已确定的符号引用和虚方法表. 在过去(当自定义类加载器使用不普 ...

  7. Java中的栈,堆,方法区和常量池

    要说Java中的栈,堆,方法区和常量池就要提到HotSpot,HotSpot是Sun JDK 和 Open JDK中所带的虚拟机. (Sun JDK 和 Open JDK除了注释不同,代码实现基本上是 ...

  8. String放入运行时常量池的时机与String.intern()方法解惑

    运行时常量池概述 Java运行时常量池中主要存放两大类常量:字面量和符号引用.字面量比较接近于Java语言层面的常量概念,如文本字符串.声明为final的常量值等. 而符号引用则属于编译原理方面的概念 ...

  9. JVM体系结构之七:持久代、元空间(Metaspace) 常量池==了解String类的intern()方法、常量池介绍、常量池从Perm-->Heap

    一.intern()定义及使用 相信绝大多数的人不会去用String类的intern方法,打开String类的源码发现这是一个本地方法,定义如下: public native String inter ...

随机推荐

  1. Cogs 465. 挤牛奶

    465. 挤牛奶 ★   输入文件:milk2.in   输出文件:milk2.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 三个农民每天清晨5点起床,然后去牛棚给3 ...

  2. 51nod 1781 Pinball(线段树)

    题面 Pinball的游戏界面由m+2行.n列组成.第一行在顶端.一个球会从第一行的某一列出发,开始垂直下落,界面上有一些漏斗,一共有m个漏斗分别放在第2~m+1行,第i个漏斗的作用是把经过第i+1行 ...

  3. [Xcode 实际操作]四、常用控件-(6)UISwitch开关控件的使用

    目录:[Swift]Xcode实际操作 本文将演示开关控件的基本用法. 开关控件有两个互斥的选项,它是用来打开或关闭选项的控件. 在项目导航区,打开视图控制器的代码文件[ViewController. ...

  4. 对不起,给pandas配表情包太难了,pandas你该这么学,No.6

    如果图片无法观看,请移步 https://blog.csdn.net/hihell 标题起的长,才能引起你的注意呢 昨天,有个家伙,留言给我说 嫌我不好好写博客 就知道给文章配表情包 在这里,郑重的回 ...

  5. Macbook sublime 安装markdown插件

    Sublime Text为3 版本 安装sublime text 插件,需要“***”,不会弄的,就可以移步了. 首先按 command + shift + p 调出安装插件的界面,输入“instal ...

  6. 解决request中文乱码问题

    因为request请求都是ISO-8859-1,而jsp页面是采用UTF-8编码,所以当传递的参数有中文时,页面会出现乱码,但是可以将取到的数据通过String的构造函数使用指定的编码类型重新构造一个 ...

  7. Linux 调优方案, 修改最大连接数(ulimit命令)

    https://blog.csdn.net/isoleo/article/details/51732687 https://www.cnblogs.com/zengkefu/p/5649407.htm ...

  8. linux笔记之基础 1

    内核命名规则: R.X.Y-Z   2.6.32-642 R: 内核有重大改变时才会更改,目前为止有四个大版本更新. X:基数为开发版,偶数为稳定版. Y.Z:修复bug,实现新功能,新特性的时候更改 ...

  9. event对象的使用注意事项

    首先event是在事件发生的时候产生的,所以必须在事件发生的事件监听函数里面使用他.不然的话就没用的.会找不到这个事件: 错误的写法: 报错的内容: 正确的写法:

  10. POJ1020 Anniversary Cake

    题目来源:http://poj.org/problem?id=1020 题目大意:有一块边长为s的正方形大蛋糕,有n个客人,每个客人想分一块边长为si的正方形蛋糕.求这块大蛋糕能否恰好满足所有客人的需 ...