【JVM】13、StringTable

本文详细介绍了JVM中StringTable的结构及其作用,讲解了String对象在不同JDK版本下的内存分配变化,以及String的基本特性和操作。探讨了字符串拼接的底层原理和效率,强调了intern()方法的使用和性能优化,同时还涉及G1垃圾收集器中的String去重操作,旨在帮助读者深入理解Java中字符串的管理和内存优化。

常量池分类

  • Class文件中的常量池
    这里面主要存放两大类常量:
    • 字面量(Literal):文本字符串等
    • 符号引用(Symbolic References):属于编译原理方面的概念,包含三类常量:
      • 类和接口的全限定名(Full Qualified Name)
      • 字段的名称和描述符(Descriptor)
      • 方法的名称和描述符
  • 运行时常量池
    方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池(Constant Pool Table),存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池。
  • 全局字符串常量池StringTable
    HotSpot VM里,记录interned string的一个全局表叫做StringTable,它本质上就是个HashSet。这是个纯运行时的结构,而且是惰性(lazy)维护的。注意它只存储对java.lang.String实例的引用,而不存储String对象的内容。 注意,它只存了引用,根据这个引用可以得到具体的String对象。
    一般我们说一个字符串进入了全局的字符串常量池其实是说在这个StringTable中保存了对它的引用,反之,如果说没有在其中就是说StringTable中没有对它的引用。

String的基本特性

  • String:字符串,使用一对 “” 引起来表示

    String s1 = "mogublog" ;   			// 字面量的定义方式
    String s2 =  new String("moxi");     // new 对象的方式
    
  • String声明为final的,不可被继承

  • String实现了Serializable接口:表示字符串是支持序列化的。实现了Comparable接口:表示String可以比较大小

  • string在jdk8及以前内部定义了final char[] value用于存储字符串数据。JDK9时改为byte[]同时基于String的数据结构,例如StringBuffer和StringBuilder也同样做了修改

    jdk8及以前: 在这里插入图片描述
    jdk9及以后:
    在这里插入图片描述

为什么 JDK9 改变了 String 的结构(char改为byte)

改为 byte[] 存储的原因
在这里插入图片描述

  • char数组中,每个字符使用两个字节(16位)。
  • 从许多不同的应用程序收集的数据表明,字符串是堆使用的主要组成部分,而且大多数字符串对象只包含拉丁字符。这些字符只需要一个字节的存储空间,因此这些字符串对象的内部char数组中有一半的空间将不会使用。

在这里插入图片描述

  • 因此String再也不用char[] 来存储了,改成了byte [] 加上编码标记,节约了一些空间
    之前 String 类使用 UTF-16 的 char[] 数组存储,现在改为 byte[] 数组 外加一个编码标志位存储,该编码标志将指定 String 类中 byte[] 数组的编码方式

  • String:代表不可变的字符序列。简称:不可变性。

  • 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。

  • 字符串常量池是不会存储相同内容的字符串的,因为底层用的hashtable
    Java语言规范里要求完全相同的字符串字面量,应该包含同样的Unicode字符序列(包含同一份码点序列的常量),并且必须是指向同一个String类实例。
    在这里插入图片描述

面试题

在这里插入图片描述

String 底层 Hashtable 结构

  • String的String Pool是一个固定大小的Hashtable
    hashtable就是数组加链表
  • 使用-XX:StringTablesize可设置StringTable的长度
  • StringTable的长度是固定的,不同的jdk版本默认值不一样
    • 在JDK6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快,StringTablesize设置的大小没有要求
      在这里插入图片描述

    • 在JDK7中,StringTable的长度默认值是60013,StringTablesize设置的大小没有要求
      在这里插入图片描述

    • 在JDK8中,StringTable的长度默认值是60013,StringTable可以设置的最小值为1009

      设置的值小于1009就报错了
      在这里插入图片描述

为什么要idk要增大stringtable的长度

如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern()方法时性能会大幅下降。

String 内存结构的分配位置

  • 在Java语言中有8种基本数据类型和一种比较特殊的类型String。这些类型为了使它们在运行过程中速度更快、更节省内存,都提供了一种常量池的概念。

  • 常量池就类似一个Java系统级别提供的缓存。8种基本数据类型的常量池都是系统协调的,String类型的常量池比较特殊。它的主要使用方法有两种。

    • 直接使用双引号声明出来的String对象会直接存储在常量池中。
      比如:String info=“atguigu.com”;
    • 如果不是用双引号声明的String对象,可以使用String提供的intern()方法。

String在不同jdk版本中存在的位置

  • Java 6及以前,字符串常量池存放在永久代
    在这里插入图片描述

  • Java 7中 Oracle的工程师对字符串池的逻辑做了很大的改变,即将字符

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值