JVM学习-String的内存分配


String 的String pool (字符串常量池)是一个固定大小的HashTable,jdk6 中是默认的数组长度是1009
如果放入String pool 中的String太多,会造成hash冲突严重,导致链表很长,链表长了对于数据的更新和读取都是有性能的下降 可以通过-XX:StringTableSize参数设置大小
jdk8 开始默认的StringTable的长度是60013,1009是可设置的最小值,如果设置的值小于这个值是不允许的

java语言有8中基本类型和一种比较特殊的类型String,这些类型为了使他们在运行中更快都提供了常量池的概念,常量池类似于java系统级别提供的缓存
直接通过双引号声明出来的String对象会直接存储在常量池中,称为字符串字面量
不是通过双引号声明的String对象可以使用String提供的intern方法往常量池中放入字符串
在java6中,字符串常量池是存储在永久代中
在java7中,常量池的位置调整到java堆中
java8调整概念为元空间,字符串常量在堆中

为什么调整
1)permSize默认比较小 2)永久代GC回收频率低

 

关于字符串拼接

1.字符串拼接字符串的结果是放在常量池中,原理是编译期优化
String s1 = "a"+"b"+"c";
String s2 = "abc";
s1 == s2 //true

2.如果拼接前后出现变量,则结果是在堆中,相当于在堆空间中new String()
String s1 = "a";
String s2 = "b";
String s3 = "ab;
String s4 = s1+s2;
s3==s4//false

String s4 = s1+s2的执行细节:
1)StringBUilder s = new StringBuilder;
2)s.append("a");
3)s.append("b");
4)s.toString

3.字符串拼接操作不一定使用StringBuilder,如果字符串前后都是字符串常量或者常量引用
则仍然适用编译期优化

final String s2 = "b";
final String s3 = "ab;
String s4 = s1+s2;
s3==s4//true
final修饰了s1 和s2,在编译期就确定了,可以理解为一个常量


4.intern方法判断字符串常量池中是否在字符串,如果存在,则返回常量池中的地址,如果不存在
则在常量池中放入,并返回常量池中存在该对象的地址

 

new String("ab") 创建了几个对象
1.new关键字的操作首先会在堆中创建一个ab对象
2.字符串常量池中放入ab对象(字节码指令ldc)


new String("a")+ new String("b") 创建了几个对象

1.变量拼接,首先创建一个 StringBuilder
2.new操作堆中创建一个a的对象
3.字符串常量池中放入对象a
4.new操作在堆中创建b
5.字符串常量池中放入对象b
6.StringBuilder的toString方法会new 一个String对象,但是该对象不会在常量池中

 

posted on 2020-05-26 22:44  Flower2021  阅读(381)  评论(0编辑  收藏  举报