jmap适合离线分析堆快照,Arthas支持在线实时探查;jmap需配合MAT或jhat统计String分布,Arthas可用vmtool、OGNL、trace等命令快速定位字符串数量、长度及来源。

在 Java 应用中排查内存占用高、字符串冗余或重复等问题时,统计堆中字符串(尤其是 java.lang.String)的分布情况非常关键。jmap 和 Arthas 是两种常用工具,但能力与适用场景不同:jmap 适合离线快照分析,Arthas 支持在线实时观察,且对字符串内容分析更友好。
用 jmap + jhat 或 MAT 分析字符串对象分布
jmap 本身不直接支持按字符串内容分组统计,但可导出堆快照(hprof),再借助其他工具深入分析:
- 先用
jmap -dump:format=b,file=heap.hprof <pid>生成堆转储文件 - 用
jhat heap.hprof启动本地 Web 分析服务(默认端口 7000),访问http://localhost:7000→ “Show heap histogram” 可查看所有类实例数量和浅堆大小,搜索java.lang.String行,得到总数量和总 shallow size - 更推荐用 Eclipse MAT(Memory Analyzer Tool)打开 hprof 文件:
– 使用 “Dominator Tree” 视图,筛选java.lang.String,右键 → “Group By: Value”(需启用“Parse String Values”选项)
– 或运行 OQL 查询:SELECT s.value, COUNT(*) FROM java.lang.String s GROUP BY s.value ORDER BY COUNT(*) DESC(MAT 1.10+ 支持) - 注意:JDK 9+ 默认关闭字符串去重(String Deduplication),若开启过(
-XX:+UseStringDeduplication),MAT 中相同 value 的 String 实例可能共享 char[]/byte[],OQL 统计结果会更准确反映“语义唯一字符串”的分布
用 Arthas 快速统计字符串实例数量和长度分布
Arthas 更适合线上轻量级探查,虽不能直接展示所有字符串值(避免敏感信息泄露和性能冲击),但能高效获取结构化分布信息:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 连接目标进程:
arthas-boot.jar <pid> - 统计当前存活的 String 实例总数及平均长度:
ognl '@java.lang.management.ManagementFactory@getMemoryMXBean().getHeapMemoryUsage().getUsed()'(先看堆使用量)vmtool --action getInstances --className java.lang.String --limit 1000 | grep -v "null" | wc -l(粗略取样计数) - 更实用的是结合 OGNL 查看典型字符串长度分布(避免全量遍历):
ognl '#strs = @java.util.ArrayList@new(), #ctx=@com.taobao.arthas.core.advisor.AdviceContext@current(), #instances = @java.util.ArrayList@new(), #vmTool = @com.taobao.arthas.core.command.monitor200.VmTool@new(), #vmTool.getInstances("java.lang.String", #instances, 500), #instances.{#strs.add(#this.value.length())}, #strs' | head -n 20
这段命令取最多 500 个 String 实例,收集其底层字符数组长度(即字符串 length),可用于判断是否存在大量超长字符串 - 如需检查某类业务字符串(如 JSON、URL),可配合条件筛选:
vmtool --action getInstances --className java.lang.String --express '#this.toString().startsWith("https://")' --limit 100
进阶技巧:定位重复字符串或大字符串来源
单纯数量多未必是问题,关键是识别“谁创建了大量相似/超长字符串”:
立即学习“Java免费学习笔记(深入)”;
- 用 Arthas 的
trace监控 String 构造方法调用热点:trace java.lang.String <init> -n 5(跟踪前 5 次构造调用栈)trace java.lang.StringBuilder toString -n 10(常被忽略的 StringBuilder.toString() 场景) - 开启 JVM 参数辅助诊断:
–-XX:+PrintStringDeduplicationStatistics(JDK 8u20+)查看去重效果
–-XX:+UseG1GC -XX:+G1PrintRegionLivenessInfo(G1 GC 下辅助分析老年代字符串驻留) - 若怀疑日志、序列化或 HTTP 响应体导致字符串堆积,可用
watch观察关键方法返回值:watch com.example.service.UserService getUserInfo returnObj -x 3(查看返回对象是否含大字符串字段)
注意事项与避坑点
实际操作中容易忽略的关键细节:
- jmap dump 会触发 Full GC(取决于 JVM 版本和参数),生产环境慎用;建议加
-F强制(仅当进程无响应时)并提前评估影响 - Arthas 的
vmtool --action getInstances在高并发下可能耗时较长,--limit必须设合理上限(如 1000),否则 OOM 或卡顿 - JDK 9+ 中 String 内部由
byte[]+coder字段表示(非固定 char[]),直接读#this.value可能是 byte 数组,长度不等于字符串 length;应优先用#this.length() - MAT 中 “Group By: Value” 需勾选 “Parse String Values”,否则只按引用分组;OQL 查询在大数据量下可能超时,建议先导出子集

















