【调优】Java 调优学习笔记之字符串
一、紧凑字符串(Compact Strings)
-  核心机制: 
 Java 9 引入Compact Strings特性(Java 11 默认开启-XX:+CompactStrings),当字符串仅包含 Latin-1 字符(ASCII 范围,0-255) 时,使用 8 位字节数组(byte[]) 存储;若包含非 Latin-1 字符,则仍使用 16 位字符数组(char[])。
 ⚠️ 注意:Java 8 及之前版本统一使用char[](每个字符占 2 字节,属于 16 位字符数组)。
-  内存优化效果: 
 对于纯 Latin-1 字符串场景,Java 11 的内存占用约为 Java 8 的 75%(字符存储字节数减半)。在常规 Java 应用中,字符串可能占据堆内存的 50% 以上,因此优化效果显著。
二、重复字符串处理
1. 字符串去重(String Deduplication)
-  开启条件: - 自 Java 8 Update 20(JDK 8u20) 引入,需通过 -XX:+UseStringDeduplication开启(默认false)。
- 必须搭配 G1 垃圾收集器(需添加 -XX:+UseG1GC),且仅对 老年代字符串 生效。
 
- 自 Java 8 Update 20(JDK 8u20) 引入,需通过 
-  未默认开启的原因: - GC 停顿时间增加:去重操作由 G1 回收线程在 新生代回收 或 混合回收阶段 同步执行,需扫描存活字符串并合并重复项,可能延长 STW(Stop The World)时间。
- 内存开销风险:若重复字符串较少,去重所需的 哈希表存储(记录唯一字符串) 和 元数据追踪 可能导致内存占用增加。
 
2. 字符串驻留(String.intern ())
-  机制说明: 
 String.intern()会将字符串存入 字符串常量池(位于 JVM 堆外的元空间),而非原生内存。- Java 8 及之后,常量池的哈希表初始大小为 60013(可通过 -XX:StringTableSize调整为质数,如 1009、32791)。
- 当存储的字符串数量超过哈希表容量时,会发生 哈希碰撞,碰撞的字符串以 链表 形式存储。
 
- Java 8 及之后,常量池的哈希表初始大小为 60013(可通过 
-  性能隐患: 
 链表过长会导致intern()查询时间复杂度退化为 O (n),建议:- 避免在循环中频繁调用 intern();
- 对长字符串或大量唯一字符串,慎用 intern()。
 
- 避免在循环中频繁调用 
补充说明
-  分析工具: - jmap -histo:live <pid>:分析堆中字符串实例数量及占比(- java.lang.String条目)。
- -XX:+PrintStringDeduplicationStatistics:打印去重统计信息(如去重率、节省内存量)。
 
-  参数调优示例: # Java 11 调优参数示例(开启紧凑字符串、G1 GC、字符串去重) java -XX:+CompactStrings -XX:+UseG1GC -XX:+UseStringDeduplication -jar app.jar
