1.压缩字符串
1.1.Java 6
1.2.实验性
1.3.compressed string
2.字符串
2.1.Java 8
2.2.所有都会编码为16位字符数组
3.紧凑字符串
3.1.Java 11
3.2.compact string
3.3.8位字节数组
3.3.1.节约大量内存
3.4.-XX:+CompactStrings标志控制的
3.4.1.默认是true
3.5.很成熟且性能良好
3.6.例外是应用程序中所有的字符串都需要16位编码
3.6.1.在紧凑字符串中对这些字符串进行操作的时间可能会稍长一些
4.删除重复字符串
4.1.G1 GC执行自动去重
4.1.1.让JVM找到重复字符串后去重(deduplicate)
4.1.1.1.使用G1 GC并指定-XX:+UseStringDeduplication标志时才能做到
4.1.1.2.存在于20版本之后的Java 8和所有版本的Java 11中
4.1.1.3.默认是false
4.1.2.默认情况下没有开启的原因
4.1.2.1.在G1 GC的新生代回收和混合回收阶段进行额外的处理,这会延长回收的时间
4.1.2.2.需要一个额外的线程与应用程序线程同时运行,这可能会占用应用程序线程的CPU周期
4.1.2.3.重复字符串很少,那么应用程序的内存使用量会更高(而不是更低),这些额外占用的内存来自于跟踪所有字符串以寻找重复而产生的簿记工作
4.1.3.运行时
4.1.3.1.Java 8的-XX:+PrintStringDeduplicationStatistics标志
4.1.3.2.Java 11的-Xlog:gc+stringdedup*=debug标志
4.1.4.晋升的字符串可以进行去重的时间点
4.1.4.1.-XX:StringDeduplicationAgeThreshold=N标志控制的
4.1.4.2.默认值是3
4.2.String类的intern()方法来创建字符串的标准化版本
4.3.自定义方法来创建字符串的标准化版本
5.字符串保留
5.1.使用String类的intern()方法
5.1.1.查看字符串表的执行情况
5.1.1.1.-XX:+PrintStringTableStatistics标志运行你的应用程序
5.1.1.2.默认是false
5.1.2.只有当应用程序在一组相同长度的字符串上进行大量的重复比较时,才可以预期字符串比较能从intern()方法的使用中受益
5.1.3.intern()方法的性能是由字符串所在哈希表大小的优化程度主导的
5.2.原生哈希表有固定的大小
5.2.1.Java 8中是60 013
5.2.2.Java 11中是65 536
5.2.3.32位的Windows JVM,这个大小是1009
5.2.4.-XX:StringTableSize=N标志来设置
5.2.4.1.默认值分别为1009、60 013或65 536
5.2.5.哈希表包含一个数组
5.2.5.1.该数组可以容纳一定数量的条目
5.2.5.2.数组中的每个元素被称为一个桶
5.2.5.3.当两个对象被映射到同一个桶时,称为碰撞(collision)
5.3.jmap命令
5.3.1.获得应用程序分配的保留字符串数量
5.3.2.获得应用程序分配的保留字符串的总大小
5.4.String.equals()方法是相当快的
5.4.1.不等长的字符串永远不会相等
5.4.2.字符串的长度相等,它会扫描字符串并比较所有的字符(直到发现有字符串不匹配)
5.5.自定义字符串保留
5.5.1.自定义映射的优势在于,它不需要事先设定大小,而可以根据需要自行调整大小
5.5.2.GC压力才是真正的重
6.字符串连接
6.1.-XX:+OptimizeStringConcat标志来控制
6.1.1.默认值为true
6.1.2.在Java 11中,javac编译器会产生完全不同的字节码
6.1.2.1.该字节码会调用JVM中的一个特殊方法来优化字符串连接
6.2.JDK 8的优化在处理字符串和整数时效果很好
6.2.1.但无法处理双精度浮点数(以及大多数其他类型的数据)
6.2.1.1.Java11可以
6.3.当你转到一个较新的版本时,不需要重新编译旧代码,因为字节码会是一样的
6.3.1.用Java 8编译执行字符串连接的代码,然后用Java 11运行它,Java 11 JDK采用的优化会和Java 8的相同
6.3.1.1.代码仍然会被优化,并且运行得相当快
6.4.想用新的编译器编译出新的代码,以使用新的语言特性
6.4.1.用Java 11重新编译该代码,字节码会使用新的优化,它可能会更快
6.5.千万不要在循环中使用字符串连接,除非连接的字符串不会在循环的下一次迭代中使用
6.5.1.否则,永远要显式地使用StringBuilder对象来获得更好的性能
6.5.2.可以在(逻辑上的)单行中完成连接时,就不要害怕使用它