Java教程

【JVM Ⅳ】StringTable字符串表

本文主要是介绍【JVM Ⅳ】StringTable字符串表,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、String 的基本特性:

String 的不可变性

【基本特性】final修饰、实现Serialize跨进程、Comparable可比较用作排序;
【解释】不可变的字符序列,它是存储在堆区的常量池中的(两种办法:""、intern()都可以。)
【变化】JDK1.8char型数组存储,1.9之后使用的是byte型数组存储。

String的底层Hashtable结构

【解释】字符串常量池中是不会存储相同内容的字符串的,字符串数组和链表的博弈,StringTablSize 。

cmd查看参数:

jps查看Java Virtual Machine Process Status Tool,查看虚拟机进程

option:
jinfo -flag StringTableSize 进程id

  • no option 输出全部的参数和系统属性
  • -flag name 输出对应名称的参数
  • -flag [+|-]name 开启或者关闭对应名称的参数
  • -flag name=value 设定对应名称的参数
  • -flags 输出全部的参数
  • -sysprops 输出系统属性

在这里插入图片描述

二、String内存分配

放在堆中,

String内存结构的分配位置

【变化】1.6字符串常量在永久代:极少GC导致OOM更易出现;1.7字符串常量池放在堆中,调优的时候只需要改变堆的大小。

三、字符串基本操作

字符串常量池

码点序列一致就不需要重新加载String实例。

四、字符串拼接操作

  • 常量和常量的拼接结果在常量池,原理是编译期优化。
  • 只要其中有一个是变量,结果就等于在堆空间中new StringBuilder()。变量拼接的原理是 StringBuilder对象

底层原理:

  • 变量被final修饰为常量,两边都是常量就是普通的字符串拼接,会采用编译器优化在字符串常量池中加载一个字符串。

拼接操作和append进行对比

拼接操作的效率更低,因为涉及到两个操作:new StringBuilder和底层的toString下的new String对象。占用的内存也更多,GC更加频繁。
append只有本身的一个对象。

五、intern()

把对象放入字符串常量池的方法:有的直接拿,没有直接加载新的

String的intern方法使用:

本不存在就给引用或者""对象。

  • 1.6:new String(“abc”)在堆中创建一个对象,并且在常量池里面也创建一个对象"abc"。
    • 找不到就傻傻的(把此对象复制一份)重新创建一份在串池中。
  • 1.7:两个String拼接起来还是一个String对象,但是这是没有在字符串常量池中保存数据的。
    • new String 的时候反正大家都有"abc"了,那么我只保留一个引用地址,就可以直接指向String对象,方便节省空间。
    • 如果没有,则会把对象的引用地址复制一份,放入串池,并返回串池中的引用地址

在这里插入图片描述

大的网站平台,需要内存中存储大量的字符串。字符串都调用 intern() 方法,就会明显降低内存的大小。

intern方法的实现

    public static void main(String[] args) throws InterruptedException {
        String s1 = new String("a") + new String("b");
        String s2 = "ab";
        String s3 = new String("ab");
//        s3 =等价于= s1+s2
    }

六、G1的String去重操作

干掉new 出来的重复String对象!

  • 使用一个hashtable来记录所有的被string对象使用的不重复的char数组。当去重的时候,会查这个hashtable,来看堆上是否已经存在一个一模一样的char数组。

  • 如果存在,string对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉。

这篇关于【JVM Ⅳ】StringTable字符串表的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!