JVM - 垃圾回收调优 (GC Tuning)
JVM 垃圾回收调优 (GC Tuning)
GC调优是高级Java工程师必须具备的核心技能之一。它不是一个“一招鲜”的技术,而是一个需要明确目标、分析日志、不断实验的系统性工程。
1. GC 调优的核心指标(目标)
在开始调优之前,必须明确你的业务场景和调优目标。GC调优主要关注三大核心指标,它们之间通常存在“跷跷板效应”,难以同时达到最优。
-
吞吐量 (Throughput)
- 定义:CPU用于执行用户代码的时间占总运行时间的比例。即
用户代码执行时间 / (用户代码执行时间 + GC时间)。 - 适用场景:追求在长时间内完成尽可能多的工作,对单次停顿不敏感的后台计算密集型任务(如大数据批处理、科学计算、报表生成)。
- 定义:CPU用于执行用户代码的时间占总运行时间的比例。即
-
停顿时间 (Pause Time)
- 定义:垃圾收集器工作时,暂停所有用户线程("Stop-The-World", STW)的时长。
- 适用场景:对响应时间非常敏感的与用户交互的在线服务(如Web网站、API服务、交易系统)。低停顿时间意味着更流畅的用户体验。
-
内存占用 (Footprint)
- 定义:Java堆所占用的内存大小。
- 适用场景:对内存资源有限制的场景(如嵌入式设备、高密度部署的微服务)。
总结:调优前必须做出取舍。后台任务优先保证吞吐量;在线服务优先保证低停顿时间。
2. 以“降低停顿时间”为目标的调优思路
这是在线服务最常见的调优目标。
第一步:选择合适的收集器
- 在现代Java版本(JDK 8u40+)和有足够内存(>6G)的服务器上,G1收集器通常是首选。
- 开启G1:
-XX:+UseG1GC(含义: 显式开启G1垃圾收集器)
- 开启G1:
第二步:设定明确的停顿时间目标
- 这是G1调优的核心。通过设置一个期望的最大停顿时间,让G1去自动调整内部参数来达成这个目标。
- 常用参数:
-XX:MaxGCPauseMillis=200(含义: 设置G1收集器单次STW停顿时间的最大期望值为200毫秒。这是一个“软目标”,G1会尽力达成,但不100%保证。)- 注意:此值不宜设置得过小(如<50ms),否则可能导致GC过于频繁,吞吐量急剧下降。
第三步:开启并分析GC日志
GC调优离不开GC日志,它是调优的“眼睛”。
- 开启GC日志 (JDK 9+):
-Xlog:gc*:file=gc.log:time,level,tags:filecount=5,filesize=10m- 参数解释:
gc*: 记录所有GC相关的日志信息。file=gc.log: 将日志输出到当前目录下的gc.log文件。time,level,tags: 定义日志内容的格式,包含时间戳、日志级别和标签。filecount=5,filesize=10m: 启用日志滚动。最多保留5个日志文件,每个文件最大为10MB。
- 参数解释:
- 通过分析日志,我们可以看到GC的频率、耗时、原因等,然后进行针对性调整。
第四步:进行针对性调整
-
调整新生代大小:
- 很多STW停顿由新生代的Minor GC引起。如果新生代太小,会导致频繁的Minor GC。
- 常用参数:
-Xmn: (含义: 直接设置新生代的绝对大小,优先级高于-XX:NewRatio)-XX:NewRatio: (含义: 设置老年代与新生代的内存大小比例)-XX:SurvivorRatio: (含义: 设置新生代内部Eden区与单个Survivor区的大小比例)
- 思路:观察Minor GC频率和耗时,尝试增大新生代(如
-Xmn4g),看是否能有效降低GC频率,同时单次停顿时间仍在可接受范围内。
-
调整对象晋升阈值:
- 常用参数:
-XX:MaxTenuringThreshold=15(含义: 对象在新生代Survivor区最多经历15次Minor GC后晋升到老年代) - 思路:如果发现大量生命周期不长的对象过早进入老年代,导致频繁的Full GC/Mixed GC,可以尝试调高此阈值,让对象在新生代多停留一段时间。
- 常用参数:
-
调整G1的老年代GC触发时机:
- 常用参数:
-XX:InitiatingHeapOccupancyPercent=45(含义: 当老年代已用堆内存的百分比达到45%时,触发G1并发标记周期) - 思路:当老年代使用率达到此阈值时,G1会启动并发标记周期。如果GC日志显示堆空间耗尽前未能完成老年代的回收(导致Full GC),可以尝试降低此值,让G1更早地开始回收老年代。
- 常用参数:
总结调优思路:
- 选择G1收集器。
- 设置一个合理的停顿时间目标 (
MaxGCPauseMillis)。 - 打开GC日志进行监控。
- 分析日志,调整新生代大小 (
-Xmn) 来平衡Minor GC的频率和单次耗时。 - 如果老年代GC有问题,调整触发阈值 (
InitiatingHeapOccupancyPercent) 或 对象晋升阈值 (MaxTenuringThreshold)。

浙公网安备 33010602011771号