You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何JVM存在大量未被回收的char数组与String对象?

JVM堆中非存活char数组/String对象相关问题解答

1. jmap -histo与jmap -histo:live的核心差异

  • jmap -histo:不会触发GC,直接统计堆内所有已分配内存的对象,包含已经失去引用、等待GC回收的垃圾对象,你看到的1000M+char数组就是所有已分配的char数组总大小。
  • jmap -histo:live:执行前会主动触发一次Full GC,仅统计GC后仍然存活的、有引用链可达的对象,你看到的140M就是当前真正在用的char数组大小。

两者的差值860M就是已经死亡、等待被GC回收的char数组总大小,并不是凭空消失了。

2. 该情况是否正常、是否需要关注

  • 绝大多数场景下属于正常现象,不需要特殊处理:JVM的GC本身是懒执行的,不会对象一失去引用就立刻回收,频繁GC反而会浪费CPU资源,只要GC频率、单次GC耗时符合业务预期,堆内存剩余充足,就无需干预。
  • 需要关注排查的场景:
    • 堆内存使用率长期居高不下,GC触发频繁、单次STW耗时过高,已经影响业务吞吐量或请求延迟
    • 每次统计的非存活String/char数组大小持续暴涨,需要排查代码是否存在不必要的大批量字符串生成逻辑

3. 死亡对象未被回收的原因、回收时机

  • 未回收原因:GC还未触发。不同GC回收器的触发条件不同:新生代内存占满会触发Young GC清理新生代垃圾,老年代占用达到对应阈值(如CMS的-XX:CMSInitiatingOccupancyFraction设置值、G1的IHOP动态阈值)会触发Old GC/Full GC清理全堆垃圾,未到触发阈值时死亡对象会暂时占用内存。
  • 回收时机:当对应内存区域的占用达到GC触发阈值时,GC执行过程中就会自动清理所有无引用的死亡对象,释放对应内存。

4. 手动触发GC释放内存的方法

如果你的JVM没有配置-XX:+DisableExplicitGC参数,可通过以下两种方式手动触发Full GC立即释放这部分内存:

  • 直接执行jmap -histo:live {pid},命令执行过程中就会自动触发Full GC
  • 执行jcmd {pid} GC.run主动触发Full GC

注意:生产环境手动触发Full GC会产生STW停顿,请避开业务高峰执行,避免影响正常业务请求。如果配置了-XX:+DisableExplicitGC参数,手动触发GC的命令会失效,只能等待JVM自动触发GC。

内容的提问来源于stack exchange,提问作者Zhang Buzz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 23:36:04