常量池与方法区以及又读new String对象创建问题
又拿出这道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对象创建问题的更多相关文章
- JDK方法区、元空间区别 & String.intern相关面试题
一.方法区.永久代.元空间 1.方法区.永久代 方法区也是各个线程共享的内存区域,它用于存储已经被虚拟机加载的类信息.常量.静态变量.即时编译器编译后的代码等数据.方法区域又被称为"永久代& ...
- jvm之java类加载机制和类加载器(ClassLoader),方法区结构,堆中实例对象结构的详解
一.类加载或类初始化:当程序主动使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载.连接.初始化3个步骤来对该类进行初始化.如果没有意外,JVM将会连续完成3个步骤. 二.类加载时机: 1 ...
- 类的加载,链接和初始化——1运行时常量池(来自于java虚拟机规范英文版本+本人的翻译和理解)
加载(loading):通过一个特定的名字,找到类或接口的二进制表示,并通过这个二进制表示创建一个类或接口的过程. 链接:是获取类或接口并把它结合到JVM的运行时状态中,以让类或接口可以被执行 初始化 ...
- Java方法区和运行时常量池溢出问题分析
运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池 ...
- Java方法区和运行时常量池溢出问题分析(转)
运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池 ...
- 对于JVM中方法区,永久代,元空间以及字符串常量池的迁移和string.intern方法
在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法信息(如字节码,栈和变量大小),运行时常量池,已确定的符号引用和虚方法表. 在过去(当自定义类加载器使用不普 ...
- Java中的栈,堆,方法区和常量池
要说Java中的栈,堆,方法区和常量池就要提到HotSpot,HotSpot是Sun JDK 和 Open JDK中所带的虚拟机. (Sun JDK 和 Open JDK除了注释不同,代码实现基本上是 ...
- String放入运行时常量池的时机与String.intern()方法解惑
运行时常量池概述 Java运行时常量池中主要存放两大类常量:字面量和符号引用.字面量比较接近于Java语言层面的常量概念,如文本字符串.声明为final的常量值等. 而符号引用则属于编译原理方面的概念 ...
- JVM体系结构之七:持久代、元空间(Metaspace) 常量池==了解String类的intern()方法、常量池介绍、常量池从Perm-->Heap
一.intern()定义及使用 相信绝大多数的人不会去用String类的intern方法,打开String类的源码发现这是一个本地方法,定义如下: public native String inter ...
随机推荐
- 洛谷P3006 [USACO11JAN]瓶颈Bottleneck(堆模拟)
传送门 感觉这题的思路还是挺不错的.然而为啥全网就一个题解而且只有代码……然后我只好看着代码理解了好久…… 题意就是有一棵树,每一个节点向他父亲节点连边,且有一个容量表示每一秒可以经过的牛的数量,每一 ...
- java整理(二)
1.this关键字.this表示属性,表示方法和当前对象. this.属性调用属性. 方法分为两类,构造方法和普通方法,他们的调用形式是不同的.调用本类的方法this.方法()(这是调用普通方法)如果 ...
- k8s 部署应用程序
k8s相关工具介绍: Kubeadm Kubeadm解决了处理TLS加密配置.部署核心Kubernetes组件和确保其他节点可以轻松地加入集群的问题.生成的集群通过RBAC等机制得到保护. 有关Kub ...
- PHP下载远程图片的几种方法总结
1. 使用file_get_contents function dlfile($file_url, $save_to) { $content = file_get_contents($file_url ...
- input[checkbox],input[radiobox]的一些问题
复选框和文字对不齐:checkbox复选框的一些深入研究与理解: 解决方案:复选框或单选框与文字对齐的问题的深入研究与一 实例:实例.
- Python Unittest - Test Fixtures 测试夹具
一.什么是测试夹具 定义单个或者多个测试所需的环境准备(setUp),以及环境清理(tearDown). 例:连接数据库,或者创建Selenium WebDriver driver实例 二.测试夹具有 ...
- QT LCDNumber使用
新建一个QT工程 然后在cpp文件中写入代码 #include "hello.h" #include <qthread.h> #include <QVariant ...
- Unity 关于激活
- IIS下FTP服务器的PASV端口范围修改方法
应该有不少使用IIS自带的FTP服务器,IIS的FTP里的PASV模式下默认端口范围1024 - 65535,连接时会从中随机选择到响应.这样的超大范围就给服务器安全带来的隐患. 虽然可以通过一些方法 ...
- postgresql安装,java简单使用postgresql
一 整合 由于本人的学过的技术太多太乱了,于是决定一个一个的整合到一个springboot项目里面. 附上自己的github项目地址 https://github.com/247292980/spri ...