聊聊JVM中的几种常量池

目录

Class文件常量池

运行时常量池

字符串常量池

对象池

在Java虚拟机(JVM)的世界中,常量池是一个备受瞩目的话题。它不仅是内存管理的关键组成部分,还直接影响着程序的性能和资源利用率。在本文中,我们将探讨Java中几种主要常量池的实现方式,以及它们在不同版本JDK中的变化和优化。


Class文件常量池

当Java源文件经过编译后,会生成对应的Class文件。

图片

在Class文件中,开头的4个字节用于存储魔数(Magic Number),用于验证文件是否为JVM可接受的格式;紧接着的4个字节用于存储版本号,其中前2个字节表示次版本号,后2个字节表示主版本号;常量池紧随其后,用于存放常量。在Java虚拟机加载Class文件时,这些信息会被存储在方法区。

常量池主要包括两种类型的常量:字面量,类似于Java语言层面的常量,例如文本字符串和声明为final的常量值;符号引用,属于编译原理的概念。通过javap命令生成更可读的JVM字节码指令文件:

图片

字面量

在Java中,字面量指的是字符串常量或数值常量,它们只能作为右值出现,也就是等号右边的值。例如,在表达式 int a=1 中,1 就是字面量。

符号引用

      符号引用是编译原理中的概念,相对于直接引用而言。主要包括三类常量:类和接口的全限定名,字段名称和描述符,方法名称和描述符。举例来说,在之前提到的表达式中,a 就是一个字段名称,也是一种符号引用。


运行时常量池

图片

运行时常量池也是方法区的一部分。当Class文件被加载到内存后,Java虚拟机会将其中的内容转移到运行时常量池中,对应的符号引用会被转变为内存中代码的直接引用,这就是动态链接。

由于Java语言并不要求常量只能在编译期产生,因此不是只有预置入Class文件中常量池的内容才能进入方法区的运行时常量池,在运行期间,也可以将新的常量放入池中。


字符串常量池

设计思想

在我们的工作中,String类是一种极其常用的对象类型,因此为了提高性能和节省内存,JVM维护了一个特殊的内存空间,即字符串常量池。这类似于缓存区,在创建字符串常量时,首先会检查字符串常量池中是否存在该字符串,如果存在则返回引用实例,如果不存在,则会在常量池中创建一个新对象,再返回引用。

但是,值得注意的是,字符串池的实现前提是String对象是不可变的。这样可以确保多个引用同时指向字符串池中的同一个对象。如果字符串是可变的,一个引用的操作改变了对象的值,会对其他引用产生影响,这是不合理的。

字符串创建

在创建字符串对象时,有几种不同的方式。

字面量方式

使用字面量方式创建的字符串对象只会存在于常量池中。在创建对象时,JVM会首先在常量池中通过equals(key)方法判断是否存在相同的对象。如果存在,则直接返回该对象在常量池中的引用;如果不存在,则会在常量池中创建一个新对象,再返回引用。

new String()

另一种方式是使用new String()关键字,这会在堆中创建一个对象,同时也会存在于字符串常量池中。

JVM首先会在字符串常量池中查找是否存在相同的字符串对象,如果有,则不在池中再去创建,而是直接在堆中创建一个对象,然后返回堆中对象的引用。如果没有,则首先在字符串常量池中创建一个字符串对象,然后再在堆中创建一个相同的对象,最后返回堆中对象的引用。

intern()

另外,还有一个方法是使用intern()方法。这是一个本地方法,调用intern()方法时,如果字符串在字符串常量池中存在对应的字面量,则返回该字面量的地址;如果不存在,则创建一个对应的字面量,并返回其地址。

字符串常量池位置变迁

  • Jdk1.6及以前运行时常量池在永久代,其中包含字符串常量池;

  • Jdk1.7字符串常量池从永久代里的运行时常量池分离到堆中;

  • Jdk1.8及之后运行时常量池在元空间,字符串常量池里仍然在堆里;。

总结

     字符串常量池的存在避免了频繁创建相同内容的字符串,从而节省了内存,并减少了创建相同字符串耗费的时间,提升了性能。同时字符串常量池牺牲了在常量池中遍历对象所需的时间,不过这种时间成本相对较低。


对象池

对于Java中基本类型的包装类,大部分都实现了常量池技术(严格来说应该称为对象池,在堆上),包括Byte、Short、Integer、Long、Character、Boolean,而另外两种浮点数类型的包装类则没有实现。

此外,Byte、Short、Integer、Long、Character这五种整型的包装类只有在对应值小于等于127时才可以使用对象池,也就是说,对象池不负责创建和管理大于127的这些类的对象。这是因为一般来说,这些较小的数值被使用的概率相对较大。如果超出了对应范围,仍然会去创建新的对象。


欢迎关注微信订阅号:技术勘察馆

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值