【JVM--StringTable字符串常量池】

1. String 的基本特性

  • String 声明为 final 的,不可被继承
  • String 实现了 Serializable 接口:表示字符串是支持序列化的。
  • String 实现了 Comparable 接口:表示 string 可以比较大小
  • String 在 jdk8 及以前内部定义了 final char[] value 用于存储字符串数据。JDK9 时改为 byte[]

String 的 String Pool 是一个固定大小的 Hashtable

2. 字符串拼接操作

  • 常量常量的拼接结果在常量池,原理是编译期优化
  • 只要其中有一个是变量,结果就在中。变量拼接的原理是== StringBuilder==
  • 如果拼接的结果调用 intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址(将堆中字符串的地址写到字符串常量池这个位置,字符串常量池中存的是堆中对象的引用)

常量与常量拼接,编译期优化:

在这里插入图片描述

只要有一个变量,就是在堆中,用string builder拼接,最后返回.tostring变为字符串

在这里插入图片描述

不使用 final 修饰,即为变量。如 s3 行的 s1 和 s2,会通过 new StringBuilder 进行拼接
使用 final 修饰,即为常量。会在编译器进行代码优化。在实际开发中,能够使用 final 的,尽量使用

在这里插入图片描述

3. intern()的使用

DK1.7 起,将这个字符串对象尝试放入串池。

  • 如果串池中有,则并不会放入。返回已有的串池中的对象的地址
  • 如果没有,则会把对象的引用地址(就是将堆中这个对象的地址)复制一份,放入串池,并返回串池中的引用地址

4. StringTable 的垃圾回收

许多大规模的 Java 应用的瓶颈在于内存,测试表明,在这些类型的应用里面,Java 堆中存活的数据集合差不多 25%是 String 对象。更进一步,这里面差不多一半 string 对象是重复的,重复的意思是说: stringl.equals(string2)= true堆上存在重复的 String 对象必然是一种内存的浪费。这个项目将在 G1 垃圾收集器中实现自动持续对重复的 string 对象进行去重,这样就能避免浪费内存。

实现

  1. 当垃圾收集器工作的时候,会访问堆上存活的对象。对每一个访问的对象都会检查是否是候选的要去重的 String 对象
  2. 如果是,把这个对象的一个引用插入到队列中等待后续的处理。一个去重的线程在后台运行,处理这个队列。处理队列的一个元素意味着从队列删除这个元素,然后尝试去重它引用的 string 对象。
  3. 使用一个 hashtable 来记录所有的被 String 对象使用的不重复的 char 数组。当去重的时候,会查这个 hashtable,来看堆上是否已经存在一个一模一样的 char 数组。
  4. 如果存在,String 对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉。
  5. 如果查找失败,char 数组会被插入到 hashtable,这样以后的时候就可以共享这个数组了。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 字符串常量池JVM中属于方法区(也称为永久代)内存分区。方法区是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。字符串常量池是方法区中的一部分,用于存储字符串常量。在JDK 8之后,方法区被取消了,取而代之的是元空间(MetaSpace),但字符串常量池仍然存放在元空间中。 ### 回答2: 字符串常量池JVM的方法区(也称为非堆区)中。 JVM将内存分为几个不同的区域,包括堆区、方法区、虚拟机栈等。而字符串常量池是方法区的一部分,用于存储在程序中直接使用的字符串常量。 在Java中,字符串常量池是一种特殊的内存存储区域,用于存储字符串常量,它的作用是提高字符串的重用性和效率。当我们使用双引号声明一个字符串时,JVM会首先在字符串常量池中查找是否存在相同内容的字符串,如果存在则直接返回引用,如果不存在则创建一个新的字符串并放入字符串常量池中。这种机制可以减少内存占用,提高程序的执行效率。 由于字符串常量池位于方法区,它是与其他线程共享的,在程序运行过程中,多个线程可以同时访问字符串常量池。而且,字符串常量池的位置是在程序的执行过程中被动态调整的,当字符串没有被引用时,JVM会自动回收字符串常量池中的空间。 总结来说,字符串常量池JVM的方法区的一部分,用于存储程序中直接使用的字符串常量,并提高字符串的重用性和效率。 ### 回答3: 字符串常量池JVM的方法区里。方法区是JVM的一个内存分区,用于存储类信息、常量、静态变量、即时编译器编译后的代码等。而字符串常量池就是方法区的一部分,用于存储字符串常量。 在Java中,当我们使用字符串字面量(如"hello")时,编译器会将其放入字符串常量池中。当程序执行时,如果再次使用相同的字符串字面量,JVM会直接从字符串常量池中取出已存在的字符串对象,而不会创建新的对象,这样可以节省内存空间。 由于字符串在Java中使用非常频繁,所以将字符串常量池放在方法区中,可以提高字符串的重用率。此外,字符串常量池的位置在方法区中也有利于GC(垃圾回收),因为当某个字符串不再被引用时,GC可以更方便地回收该字符串常量。 需要注意的是,从Java 7开始,字符串常量池被移出了PermGen空间(方法区的前身),并放置在堆中,这是因为字符串常量池中的字符串对象是可以被垃圾回收的,而且过多的字符串常量可能导致PermGen空间溢出的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值