Skip to content

JVM GC ​

GC(Garbage Collection)负责自动识别不再使用的对象,并回收它们占用的内存。学习 GC 不需要先背所有参数,先理解三个问题:对象怎么判断存活、回收会停顿多久、不同回收器在吞吐和延迟之间如何取舍。

GC 选型思路

GC 解决什么问题 ​

问题GC 的作用
对象不用了谁释放自动发现不可达对象并回收
内存碎片怎么办复制、整理或分区回收
应用能不能继续跑在 STW、并行、并发之间取舍
停顿能不能变短使用并发标记、分区回收、读写屏障等技术

GC 不保证没有内存泄漏。只要对象仍然被可达引用链持有,GC 就不能回收。

对象存活判断 ​

HotSpot 主要使用可达性分析。GC 从 GC Roots 出发,沿引用链遍历对象:

text
GC Roots -> 可达对象 -> 继续遍历

不可达对象才可能被回收。

常见 GC Roots:

  • 当前线程栈帧中的局部变量和参数。
  • 静态字段引用的对象。
  • JNI 引用。
  • 活跃线程对象。
  • 被锁持有的对象。
  • JVM 内部结构引用的对象。

排查内存泄漏时,关键不是“对象很大”,而是“谁一直引用它”。heap dump 分析的核心就是找引用链。

STW、并行、并发 ​

概念含义关注点
STW暂停应用线程,GC 独占执行停顿时间
并行多个 GC 线程一起工作,但应用线程通常暂停缩短 GC 工作时间
并发GC 线程和应用线程同时运行降低停顿

并发回收器也不是完全不停顿。初始标记、最终标记、引用处理、类卸载等阶段仍可能 STW。

常见回收器定位 ​

回收器定位常见场景
Serial简单、单线程、低资源占用小堆、工具程序、单核环境
Parallel吞吐量优先批处理、离线计算
ParNewCMS 时代的新生代并行收集器维护老系统
CMS老年代并发标记清除维护低延迟老系统
G1分区、可控停顿、通用服务端大多数服务端应用
ZGC超低延迟、大堆并发回收延迟敏感服务
Shenandoah超低延迟并发回收延迟敏感服务
Epsilon不回收性能测试、短生命周期进程

选型 ​

小应用或命令行工具 ​

优先考虑 Serial。它简单、开销低,复杂回收器的并发能力在小堆上不一定划算。

bash
-XX:+UseSerialGC

批处理或吞吐优先 ​

优先考虑 Parallel。目标是总处理时间更短,而不是每次暂停都很短。

bash
-XX:+UseParallelGC

通用服务端 ​

优先考虑 G1。它在吞吐和停顿之间比较均衡,也是现代服务端常见选择。

bash
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200

MaxGCPauseMillis 是目标,不是硬保证。设置过低可能导致 GC 更频繁、CPU 更高。

极低延迟 ​

考虑 ZGC 或 Shenandoah。它们把大部分工作并发化,适合对长暂停敏感的服务。

bash
-XX:+UseZGC

低延迟回收器可能用更多 CPU 或牺牲部分吞吐,迁移前要压测。

GC 日志 ​

JDK 9+ 推荐统一日志:

bash
-Xlog:gc*:file=gc.log:time,uptime,level,tags

关注字段:

指标含义
Pause 时间应用线程暂停多久
Young / Mixed / Full回收类型
before/after回收前后内存变化
allocation failure是否分配失败触发
humongousG1 大对象相关问题
concurrent cycle并发周期是否来得及完成

排查路径 ​

Full GC 频繁 ​

  1. 看 GC 日志确认 Full GC 触发原因。
  2. 抓 heap dump,分析老年代大对象和引用链。
  3. 判断是内存泄漏、对象生命周期过长,还是堆太小。
  4. 再调整堆大小、晋升策略或回收器。

停顿过长 ​

  1. 先确认停顿发生在 Young、Mixed 还是 Full GC。
  2. 看对象存活率和回收后释放空间。
  3. 看是否有大对象、类卸载、引用处理或系统压力。
  4. 调整目标停顿、堆大小或换低延迟回收器。

GC 后内存不下降 ​

可能原因:

  • 对象仍被静态集合、缓存、线程本地变量持有。
  • 类加载器泄漏。
  • 直接内存或 native 内存增长,不体现在堆里。
  • heap dump 抓取时机不对。

常用命令 ​

bash
jstat -gcutil <pid> 1000
jcmd <pid> GC.heap_info
jcmd <pid> GC.class_histogram
jcmd <pid> GC.heap_dump /tmp/app.hprof

生产环境抓 dump 前确认磁盘空间和停顿风险。

别急,先让缓存热一下。