JVM-常量池

  • 引子:常量池有分类,它处在一个什么位置
    我们进场说的JVM内存模型,里面线程共享的(方法区、堆),线程私有(程序计数器、栈)。这几部分JVM内存模型是一个总体,而它们下面还有一些区域划分,例如栈有虚拟机栈和本地方法栈。我们的这篇文章所说的常量池它属于方法区的一部分(但是有特殊情况,因为虚拟机由于厂商和版本的不同内存模型的划分也有些许的改变,例如String常量池在JDK7之前属于方法区,而在7之后放到了堆中)。我们常量池也有分类,例如Class常量池、String常量池、运行时常量池。具体常量池相关的知识,通过这篇文章我们在下面详细赘述。

常量池分类

JVM常量池分为三类(或者四类)

  1. Class文件常量池
  2. 运行时常量池
  3. 字符串常量池
  4. 包装类的常量池技术(缓存)(使用了常量池思想,并不是常量池)

Class文件常量池

  • class常量池简介:
    我们写的每一个Java类被编译后,就会形成一份class文件;class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References);
    每个class文件都有一个class常量池。
    JVM-常量池_第1张图片

运行时常量池

  • 运行时常量池存在于内存中,也就是class常量池被加载到内存之后的版本,不同之处是:它的字面量可以动态的添加(String#intern()),符号引用可以被解析为直接引用
  • JVM在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。在解析阶段,会把符号引用替换为直接引用,解析的过程会去查询字符串常量池,也就是我们上面所说的StringTable,以保证运行时常量池所引用的字符串与字符串常量池中是一致的。

字符串常量池

在JDK6.0及之前版本,字符串常量池是放在Perm Gen区(也就是方法区)中;
在JDK7.0版本,字符串常量池被移到了堆中了。至于为什么移到堆内,大概是由于方法区的内存空间太小了

  • 字符串常量池是什么?
    在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个Hash表,默认值大小长度是1009;这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。字符串常量由一个一个字符组成,放在了StringTable上。
    在JDK6.0中,StringTable的长度是固定的,长度就是1009,因此如果放入String Pool中的String非常多,就会造成hash冲突,导致链表过长,当调用String#intern()时会需要到链表上一个一个找,从而导致性能大幅度下降;

对字符串常量池感兴趣朋友可以看
String,StringBuffer与StringBuilder的区别
JVM调优-StringTable结构以及基本调优

包装类的常量池技术

我们在前面看到基本数据类型被放入了Class文件常量池,可是与它相关我们经常使用的包装类,这里我们就不得不说说了,它底层借鉴了常量池技术,不过底层原理是通过Static完成了一个缓存数组。具体原理大家可以看这篇博客Java中基本数据类型和包装类区别和联系

你可能感兴趣的:(#,JVM,jvm)