GC调优实战
GC调优实战
GC调优是Java性能优化的核心环节,合理的GC配置能显著降低延迟和提高吞吐量。
GC日志分析
# 启用GC日志(JDK11+)
java -Xlog:gc*:file=gc.log:time,uptime,level,tags \
-jar app.jar
# 分析GC日志
# 使用GCEasy在线分析:https://gceasy.io
# 或使用GCViewer
常用GC收集器
| 收集器 | 算法 | 适用场景 | 参数 |
|---|---|---|---|
| Serial | 串行复制 | 单核/小内存 | -XX:+UseSerialGC |
| Parallel | 并行复制 | 吞吐量优先 | -XX:+UseParallelGC |
| CMS | 并发标记清除 | 低延迟 | -XX:+UseConcMarkSweepGC |
| G1 | 分区+复制 | 大内存+低延迟 | -XX:+UseG1GC |
| ZGC | 染色指针+读屏障 | 超低延迟 | -XX:+UseZGC |
| Shenandoah | 转发指针 | 超低延迟 | -XX:+UseShenandoahGC |
G1调优
# G1推荐配置
java -XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:G1HeapRegionSize=16m \
-XX:InitiatingHeapOccupancyPercent=45 \
-XX:G1ReservePercent=10 \
-Xms8g -Xmx8g \
-jar app.jar
G1调优示例
// 监控GC情况
public class GCMonitor {
@Scheduled(fixedRate = 5000)
public void monitorGC() {
List<GarbageCollectorMXBean> gcBeans =
ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcBean : gcBeans) {
log.info("GC: {} Collections={}, Time={}ms",
gcBean.getName(),
gcBean.getCollectionCount(),
gcBean.getCollectionTime());
}
}
}
调优策略
目标设定
/**
* 调优目标
* 1. 吞吐量:CPU用于执行用户代码的时间占比 > 95%
* 2. 延迟:GC暂停时间 < 200ms(P99)
* 3. 内存:避免Full GC或尽量减少
*/
内存分配策略
# 根据应用特点配置
# - 堆内存小于4G:使用Serial或Parallel
# - 堆内存4G-16G:使用G1
# - 堆内存>16G且延迟敏感:使用ZGC或Shenandoah
# 小应用
java -XX:+UseSerialGC -Xms256m -Xmx256m -jar app.jar
# 中等应用
java -XX:+UseG1GC -Xms4g -Xmx4g -jar app.jar
# 大型低延迟应用
java -XX:+UseZGC -Xms16g -Xmx16g -jar app.jar
GC日志解读
[GC (Allocation Failure) [PSYoungGen: 65536K->10752K(76288K)]
65536K->11020K(251392K), 0.0034567 secs]
# 解读:
# - GC类型:Allocation Failure(分配失败)
# - 年轻代:65536K -> 10752K(回收了54784K)
# - 堆总量:65536K -> 11020K
# - 耗时:0.0034567秒
常见GC问题
// 问题1:频繁Young GC
// 原因:新生代太小或对象分配过快
// 解决:增大-Xmn或调整G1RegionSize
// 问题2:Full GC频繁
// 原因:老年代空间不足
// 解决:增大堆内存或优化对象生命周期
// 问题3:GC暂停时间长
// 原因:堆内存过大或使用串行收集器
// 解决:使用G1/ZGC并设置合适的暂停目标
小结
GC调优需要根据应用特点选择合适的收集器,并通过GC日志分析持续优化配置。