《Java虚拟机内存分配秘籍:StringTable大揭秘!》

StringTable

String的基本特性

  • string:字符串使用一对""引起来表示。string声明为final的,不可被继承

  • string实现了serializable接口:表示字符串是支持序列化的。

  • 实现了Comparable接口:表示string可以比较大小

  • string在jdk8及以前内部定义了final char[ ] value用于存储字符串数据。jdk9时改为byte[ ]

    • 结论: String再也不用char[]来存储啦,改成了byte[]加上编码标记,节约了一些空间。
  • string:代表不可变的字符序列。简称:不可变性。

    • 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。

    • 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

    • 当调用string的replace ()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

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

    • 字符串常量池中是不会存储相同内容的字符串的。

    • 使用**-XX : StringTablesize**可设置StringTable的长度

String的内存分配

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

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

  • 直接使用双引号声明出来的string对象会直接存储在常量池中。

    • √比如:string info = “atguigu.com” ;
  • 如果不是用双引号声明的string对象,可以使用string提供的intern()方法。这个后面重点谈

  • . Java6及以前,字符串常量池存放在永久代。

  • . Java 7 中oracle 的工程师对字符串池的逻辑做了很大的改变,即将字符串常量池的位置调整到Java堆内。

    • 所有的字符串都保存在堆(Heap)中,和其他普通对象一样,这样可以让你在进行调优应用时仅需要调整堆大小就可以了。
    • 字符串常量池概念原本使用得比较多,但是这个改动使得我们有足够的理由让我们重新考虑在Java 7 中使用string.intern ( )。
  • . Java8元空间,字符串常量在堆

字符串拼接操作

  • 1.常量与常量的拼接结果在常量池,原理是编译期优化

  • 2常量池中不会存在相同内容的常量。

  • 3.只要其中有一个是变量,结果就在堆中。变量拼接的原理是stringBuilder

    • 如果拼接符号的前后出现了变量,则相当于在堆空间中new String()
  • 4.如果拼接的结果调用intern ()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象地址。

  • 字符串拼接操作不一定使用的是StringBuilder!
    • 如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式。
  • 针对于final修饰类、方法、基本数据类型、引用数据类型的量的结构时,能使用上final的时候建议使用上。

intern()的使用

  • jdk1.6中,将这个字符串对象尝试放入串池。
    • 如果串池中有,则并不会放入。返回已有的串池中的对象的地址
    • 如果没有,会把此对象复制一份,放入串池,并返回串池中的对象地址
  • Jdk1.7起,将这个字符串对象尝试放入串池。
    • 如果串池中有,则并不会放入。返回已有的串池中的对象的地址
    • 如果没有,则会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址

G1中的String去重操作

  • **堆上存在重复的string对象必然是一种内存的浪费。**这个项目将在G1垃圾收集器中实现自动持续对重复的string对象进行去重,这样就能避免浪费内存。

  • 实现

    • 当垃圾收集器工作的时候,会访问堆上存活的对象。对每一个访问的对象都会检查是否是候选的要去重的string对象。
    • 如果是,把这个对象的一个引用插入到队列中等待后续的处理。一个去重的线程在后台运行,处理这个队列。处理队列的一个元素意味着从队列删除这个元素,然后尝试去重它引用的string对象。
    • 使用一个hashtable来记录所有的被string对象使用的不重复的char数组。当去重的时候,会查这个hashtable,来看堆上是否已经存在一个一模一样的char数组。
    • 如果存在,string对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉。
    • 如果查找失败,char数组会被插入到hashtable,这样以后的时候就可以共享这个数组了。
  • 命令行选项

    • UsestringDeduplication (bool):开启string去重,默认是不开启的,需要手动开启。
    • PrintstringDeduplicationstatistics (bool):打印详细的去重统计信息
    • stringDeduplicationAgeThreshold (uintx):达到这个年龄的string对象被认为是去重的候选对象

面试题

题目: new String ( “ab”)会创建几个对象?

  • 一个对象是:new关键字在堆空间创建的
    
  • 另一个对象是:字符串常量池中的对象"ab"。 字节码指令:ldc
    

拓展: new String ( “a”) + new String ( “b”)呢?

  • 对象1:new StringBuilder()

  • 对象2: new String(“a”)

  • 对象3: 常量池中的"a"

  • 对象4: new String(“b”)

  • 对象5: 常量池中的"b"

  • 深入剖析: StringBuilder的toString():

    • 对象6 :new String(“ab”)
    • 强调一下,toString()的调用,在字符串常量池中,没有生成"ab"

")

  • 对象5: 常量池中的"b"

  • 深入剖析: StringBuilder的toString():

    • 对象6 :new String(“ab”)
    • 强调一下,toString()的调用,在字符串常量池中,没有生成"ab"
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java-You

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值