JVM(七)JVM常量池详解

摘要:
为了提高性能并减少内存开销,JVM在实例化字符串常量时进行了一些优化:它为字符串打开字符串常量池,类似于在缓存中创建字符串常量时,它首先查询字符串是否存在于字符串常量池中,返回引用实例,并且不存在,实例化字符串并将其放入池中。三个字符串操作直接分配Strings=“fat house with dreams”//s:指向常量池中的引用PS:以这种方式创建的字符串对象将只在常量池中。

一、Class常量池解析

  定义:Class常量池可以理解为是Class文件中的资源仓库

  内容:Class文件中除了包含类的版本、字段、方法、接口等描述信息外, 还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用

  我们可以通过一个命令来查看我们字节码文件的内容:

JVM(七)JVM常量池详解第1张

字面量

  定义:字面量就是指由字母、数字等构成的字符串或者数值常量

  PS:字面量只可以右值出现【等号右边的值】如:int a = 1 这里的a为左值,1为右值。在这个例子中1就是字面量。

private int compute() {
    int a = 1;//符号引用:a 字面量:1
    int b = 2;//符号引用:b 字面量:2
    String c = "有梦想的肥宅";//符号引用:c 字面量:有梦想的肥宅
    return a + b;
}

符号引用

  符号引用是编译原理中的概念,是相对于直接引用来说的。主要包括了以下三类常量:

  • 类和接口的全限定名
  • 字段的名称和描述符
  • 方法的名称和描述符

  符号引用只有到运行时被加载到内存后,这些符号才有对应的内存地址信息,这些常量池一旦被装入内存就变成运行时常量池,也就引出了下面动态链接的概念。

  动态链接:对应的符号引用在程序加载或运行时会被转变为被加载到内存区域的代码的直接引用。

  例:compute()这个符号引用在运行时就会被转变为compute()方法具体代码在内存中的地址,主要通过对象头里的类型指针去转换直接引用。

二、字符串常量池解析

字符串常量池的设计思想

  字符串的分配和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化:

  • 为字符串开辟一个字符串常量池,类似于缓存区
  • 创建字符串常量时,首先查询字符串常量池是否存在该字符串
  • 存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中

三种字符串操作(Jdk1.7 及以上版本)

直接赋值

String s = "有梦想的肥宅"; // s :指向常量池中的引用

  PS:这种方式创建的字符串对象,只会在常量池中

  创建步骤:

  JVM会先去常量池中通过 equals(key) 方法,判断是否有相同的对象:

  • ,则直接返回该对象在常量池中的引用
  • 没有,则会在常量池中创建一个新对象,再返回引用

new String()方法创建

String s1 = new String("有梦想的肥宅"); // s1指向内存中的对象引用

  PS:这种方式会保证字符串常量池和堆中都有这个对象,没有就创建,最后返回堆内存中的对象引用

  创建步骤:

  因为有"有梦想的肥宅"这个字面量,所以会先检查字符串常量池中是否存在此字符串:

  • 不存在,先在字符串常量池里创建一个字符串对象再去内存中创建一个字符串对象"有梦想的肥宅"
  • 存在,就直接去堆内存中创建一个字符串对象"zhuge", 最后,将内存中的引用返回

intern()方法

String s1 = new String("有梦想的肥宅"); 
String s2 = s1.intern(); //【intern:是一个native方法】
System.out.println(s1 == s2); //false

  PS:这种方式创建的字符串对象,可能在常量池中存在,也可能不存在【常量池保存一个内存地址的引用,指向堆中对应的字符串对象】

  创建步骤:

  还是会去常量池找看有没有"有梦想的肥宅"这个字符串:

  • 存在,则返回池中的字符串
  • 不存在,将intern返回的引用指向当前字符串 s1  

  PS:jdk1.6版本需要将 s1 复制到字符串常量池里

三、八种基本类型的包装类和对象池

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

  PS:Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,因为一般这种比较小的数用到的概率相对较大。

public class Test {
    public static void main(String[] args) {
        //1、5种整形的包装类Byte,Short,Integer,Long,Character的对象,在值小于127时可以使用对象池
        Integer i1 = 127; //PS:这种调用底层实际是执行的Integer.valueOf(127),里面用到了IntegerCache对象池
        Integer i2 = 127;
        System.out.println(i1 == i2);//输出true

        //2、当值大于127时,不会从对象池中取对象
        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3 == i4);//输出false

        //3、用new关键词新生成对象不会使用对象池
        Integer i5 = new Integer(127);
        Integer i6 = new Integer(127);
        System.out.println(i5 == i6);//输出false

        //4、Boolean类也实现了对象池技术
        Boolean bool1 = true;
        Boolean bool2 = true;
        System.out.println(bool1 == bool2);//输出true

        //5、浮点类型的包装类没有实现对象池技术
        Double d1 = 1.0D;
        Double d2 = 1.0D;
        System.out.println(d1 == d2);//输出false
    }
}

免责声明:文章转载自《JVM(七)JVM常量池详解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇mybatis-plus登陆oracle数据库时提示“ORA-28002: 7 天之后口令将过期” 或提示 密码过期下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

(C#)调用Webservice,提示远程服务器返回错误(500)内部服务器错误

因为工作需要调用WebService接口,查了下资料,发现添加服务引用可以直接调用websevice 参考地址:https://www.cnblogs.com/peterpc/p/4628441.html 如果不添加服务引用又怎么做呢?于是又去查看怎么根据http协议调用webservice并做了个无参接口测试,如下: 但一做有参的接口调用就提示500错误...

【RabbitMQ】一文带你搞定springboot整合RabbitMQ涉及消息的发送确认,消息的消费确认机制,延时队列的实现

说明 这一篇里,我们将继续介绍RabbitMQ的高级特性,通过本篇的学习,你将收获: 什么是延时队列 延时队列使用场景 RabbitMQ中的TTL 如何利用RabbitMQ来实现延时队列 本文大纲 什么是延迟队列 延时队列,首先,它是一种队列,队列意味着内部的元素是有序的,元素出队和入队是有方向性的,元素从一端进入,从另一端取出。 其次,延时队列,最...

Java: JavaMail 初试(一)

前言:以前的我,很喜欢写东西,写一写所想所见所闻所感,但是工作之后,总不能写出让自己满意的文章,突发奇想,能否利用写博客的时机,将其写成类似散文似的博文呢?哈哈... 邮件功能尝试:作为一个小菜鸟,对于技术性的东西却有特殊的偏好,每每通过自己学习而获得新的知识,总会如孩童拥有一个新奇的玩意儿一样,欢欣雀跃。第一次写邮件功能,这一篇文章就是记录下,我在参考网...

java1.8新特性之stream

什么是Stream? Stream字面意思是流,在java中是指一个来自数据源的元素队列并支持聚合操作,存在于java.util包中,又或者说是能应用在一组元素上一次执行的操作序列。(stream是一个由特定类型对象组成的一个支持聚合操作的队列。)注意Java中的Stream并不会存储元素,而是按需计算。关于这个概念需要以下几点解释:1、数据源流的来源。...

Java 使用stringTemplate导出大批量数据excel(百万级)

目前java框架中能够生成excel文件的的确不少,但是,能够生成大数据量的excel框架,我倒是没发现,一般数据量大了都会出现内存溢出,所以,生成大数据量的excel文件要返璞归真,用java的基础技术,IO流来实现。 如果想用IO流来生成excel文件,必须要知道excel的文件格式内容,相当于生成html文件一样,用字符串拼接html标签保存到文本文...

解决Android与服务器交互大容量数据问题

对于目前的状况来说,移动终端的网络状况没有PC网络状况那么理想。在一个Android应用中,如果需要接收来自服务器的大容量数据,那么就不得不考虑客户的流量问题。本文根据笔者的一个项目实战经验出发,解决大容量数据的交互问题,解决数据大小会根据实际情况动态切换问题(服务器动态选择是否要压缩数据,客户端动态解析数据是否是被压缩的),还有数据交互的编码问题。 解决...