【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对象会被调整引用那个数组,释放对原来的数组的引用,最终会被垃圾收集器回收掉。
标签:String,对象,StringTable,拼接,JVM,字符串,new,常量 来源: https://blog.csdn.net/weixin_43801418/article/details/117882568