垃圾回收器与GC日志配置
垃圾回收器的选择和配置对Java应用的性能至关重要。本文将深入讲解主流垃圾收集器的特点、选型策略以及GC日志的配置与分析方法。
主流垃圾收集器对比
mermaid
graph LR
A["垃圾收集器"] --> B["Serial GC<br/>单线程"]
A --> C["Parallel GC<br/>并行回收"]
A --> D["CMS GC<br/>并发标记"]
A --> E["G1 GC<br/>分区回收"]
A --> F["ZGC<br/>低延迟"]
B -.适用场景.-> B1["单核CPU<br/>小内存"]
C -.适用场景.-> C1["多核CPU<br/>高吞吐量"]
D -.适用场景.-> D1["低停顿<br/>已废弃"]
E -.适用场景.-> E1["大堆内存<br/>可预测停顿"]
F -.适用场景.-> F1["超大堆<br/>毫秒级停顿"]
style A fill:#5C6BC0,stroke:#3949AB,stroke-width:3px,color:#fff
style E fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20
style F fill:#CE93D8,stroke:#7B1FA2,stroke-width:2px,color:#4A148C收集器特性对比
| 收集器 | 算法 | 线程 | STW时长 | 适用堆大小 | JDK版本 |
|---|---|---|---|---|---|
| Serial | 复制+标记整理 | 单线程 | 长 | 小于100MB | 全版本 |
| Parallel | 复制+标记整理 | 多线程 | 中等 | 中等 | 全版本,JDK8默认 |
| CMS | 标记清除 | 并发 | 短 | 中等 | JDK14移除 |
| G1 | 分区+混合 | 并发 | 可控 | 大于4GB | JDK9+默认 |
| ZGC | 着色指针 | 并发 | 毫秒级 | TB级以上 | JDK11+ |
| Shenandoah | 转发指针 | 并发 | 毫秒级 | TB级以上 | JDK12+ |
垃圾收集器启用参数
bash
# 启用Serial GC(串行收集器)
-XX:+UseSerialGC
# 启用Parallel GC(JDK 8默认,并行收集器)
-XX:+UseParallelGC
# 启用CMS GC(并发标记清除,JDK 14已移除)
-XX:+UseConcMarkSweepGC
# 启用G1 GC(JDK 9+默认)
-XX:+UseG1GC
# 启用ZGC(低延迟收集器,JDK 11+)
-XX:+UseZGC
# 启用Shenandoah GC(JDK 12+)
-XX:+UseShenandoahGCG1 GC专属调优参数
G1是目前最推荐的垃圾收集器,提供可预测的停顿时间:
mermaid
graph TB
A["G1 GC特性"] --> B["分区设计"]
A --> C["可预测停顿"]
A --> D["混合回收"]
A --> E["并发标记"]
B --> B1["堆划分为多个Region"]
B --> B2["动态调整Eden/Survivor/Old"]
C --> C1["MaxGCPauseMillis目标"]
C --> C2["智能选择回收区域"]
D --> D1["Young GC + 部分Old Region"]
D --> D2["优先回收垃圾最多的Region"]
style A fill:#5C6BC0,stroke:#3949AB,stroke-width:3px,color:#fff
style B fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20
style C fill:#64B5F6,stroke:#1976D2,stroke-width:2px,color:#0D47A1G1核心参数
bash
# 设置期望的最大GC停顿时间为200ms
-XX:MaxGCPauseMillis=200
# 设置GC工作线程数为8
-XX:ParallelGCThreads=8
# 设置并发标记线程数
-XX:ConcGCThreads=2
# 设置触发并发GC的堆使用率阈值为45%
-XX:InitiatingHeapOccupancyPercent=45
# 设置Region大小(1MB-32MB之间,2的幂)
-XX:G1HeapRegionSize=4m
# 设置混合回收时老年代Region最大占比
-XX:G1MixedGCLiveThresholdPercent=85G1参数说明
| 参数 | 说明 | 默认值 | 建议值 |
|---|---|---|---|
| MaxGCPauseMillis | 期望最大停顿时间 | 200ms | 根据SLA设置 |
| ParallelGCThreads | 并行GC线程数 | CPU核心数 | CPU核心数 |
| ConcGCThreads | 并发标记线程数 | ParallelGCThreads/4 | 保持默认 |
| InitiatingHeapOccupancyPercent | 触发并发标记的堆占用率 | 45% | 40-50% |
| G1HeapRegionSize | Region大小 | 堆/2048 | 保持默认 |
GC日志配置
JDK 8 GC日志配置
bash
# 打印详细GC信息
-XX:+PrintGCDetails
# 打印GC时间戳(日期+时间格式)
-XX:+PrintGCDateStamps
# 指定GC日志文件路径(%t为时间戳占位符)
-Xloggc:/var/logs/app/gc-%t.log
# 打印对象晋升年龄分布
-XX:+PrintTenuringDistribution
# GC前后打印堆详细信息
-XX:+PrintHeapAtGC
# 打印引用处理信息(强/软/弱/虚引用)
-XX:+PrintReferenceGC
# 打印应用暂停时间
-XX:+PrintGCApplicationStoppedTime
# 启用GC日志滚动
-XX:+UseGCLogFileRotation
# 保留最近10个日志文件
-XX:NumberOfGCLogFiles=10
# 单个日志文件最大100MB
-XX:GCLogFileSize=100MJDK 9+ 统一日志配置
JDK 9引入了统一的日志框架(Unified Logging):
bash
# 基础GC日志
-Xlog:gc:gc.log
# 详细GC日志
-Xlog:gc*:gc.log:time,uptime,level,tags
# 带日志轮转
-Xlog:gc*:file=gc.log:time,uptime:filecount=10,filesize=100M
# 分类输出
-Xlog:gc=info,gc+heap=debug,gc+phases=trace:file=gc.logGC日志输出示例解读
Young GC示例:
bash
2024-11-27T10:15:23.456+0800: [GC (Allocation Failure)
[PSYoungGen: 512000K->64000K(589824K)]
1024000K->576000K(2038400K), 0.0123456 secs]解读:
GC (Allocation Failure): Eden区分配失败触发的Young GCPSYoungGen: 512000K->64000K(589824K): 新生代从512MB回收到64MB,容量589MB1024000K->576000K(2038400K): 整个堆从1GB变为576MB,总容量2GB0.0123456 secs: GC耗时约12ms
Full GC示例:
bash
2024-11-27T10:20:45.789+0800: [Full GC (Metadata GC Threshold)
[PSYoungGen: 64000K->0K(589824K)]
[ParOldGen: 512000K->256000K(1448576K)]
576000K->256000K(2038400K),
[Metaspace: 245000K->245000K(1280000K)], 0.5432100 secs]解读:
Full GC (Metadata GC Threshold): 元空间达到阈值触发Full GC- 新生代完全清空,老年代从512MB减少到256MB
- 元空间大小未变(245MB),可能存在类加载器泄漏
- Full GC耗时543ms,需要关注
OOM异常处理配置
OOM发生场景分析
mermaid
graph TB
A["OutOfMemoryError"] --> B["Java heap space"]
A --> C["GC overhead limit exceeded"]
A --> D["Metaspace"]
A --> E["Direct buffer memory"]
A --> F["unable to create new native thread"]
B --> B1["堆内存不足<br/>检查-Xmx设置"]
C --> C1["GC耗时过多<br/>回收效果差"]
D --> D1["元空间溢出<br/>类加载过多"]
E --> E1["直接内存不足<br/>NIO使用过度"]
F --> F1["线程数超限<br/>系统资源耗尽"]
style A fill:#EF5350,stroke:#C62828,stroke-width:3px,color:#fff
style B1 fill:#FFB74D,stroke:#F57C00,stroke-width:2px,color:#E65100
style C1 fill:#FFF59D,stroke:#F9A825,stroke-width:2px,color:#F57F17
style D1 fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20OOM诊断参数配置
bash
# OOM时自动生成堆转储文件
-XX:+HeapDumpOnOutOfMemoryError
# 指定堆转储文件存放路径(%p为进程ID)
-XX:HeapDumpPath=/data/dumps/java_heap_dump_%p.hprof
# OOM时执行自定义脚本(告警/重启等)
-XX:OnOutOfMemoryError="sh /opt/scripts/oom_alert.sh %p"
# 启用GC开销限制(98%时间用于GC且回收<2%堆时抛OOM)
-XX:+UseGCOverheadLimit堆转储文件分析流程
mermaid
sequenceDiagram
participant App as 应用程序
participant JVM as JVM
participant Dump as 堆转储文件
participant Tool as 分析工具
App->>JVM: 发生OutOfMemoryError
JVM->>Dump: 生成heap dump文件
JVM->>App: 执行OnOutOfMemoryError脚本
Note over Tool: 使用MAT/JVisualVM分析
Tool->>Dump: 加载dump文件
Tool->>Tool: 分析对象引用链
Tool->>Tool: 定位内存泄漏点其他重要调优参数
字符串优化相关
bash
# 启用字符串去重(JDK 8u20+)
-XX:+UseStringDeduplication
# 设置字符串去重的对象年龄阈值
-XX:StringDeduplicationAgeThreshold=3对象晋升控制
bash
# 设置对象晋升到老年代的年龄阈值(默认15)
-XX:MaxTenuringThreshold=10
# 设置大对象直接进入老年代的阈值(字节)
-XX:PretenureSizeThreshold=1048576显式GC控制
bash
# 禁止应用代码调用System.gc()触发Full GC
-XX:+DisableExplicitGC大内存页优化
bash
# 启用大内存页(需操作系统支持)
-XX:+UseLargePages
# 设置大内存页大小
-XX:LargePageSizeInBytes=2m实战配置示例
高并发Web应用配置
bash
java -server \
-Xms8g -Xmx8g \
-Xmn3g \
-Xss512k \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-Xloggc:/logs/gc-%t.log \
-XX:+UseGCLogFileRotation \
-XX:NumberOfGCLogFiles=14 \
-XX:GCLogFileSize=50M \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/dumps/ \
-XX:+DisableExplicitGC \
-jar web-application.jar大数据批处理任务配置
bash
java -server \
-Xms16g -Xmx16g \
-XX:MetaspaceSize=512m \
-XX:MaxMetaspaceSize=1g \
-XX:+UseParallelGC \
-XX:ParallelGCThreads=8 \
-XX:+PrintGCDetails \
-XX:+PrintGCDateStamps \
-Xloggc:/logs/batch-gc.log \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/dumps/ \
-jar batch-processor.jar微服务应用配置
bash
java -server \
-Xms2g -Xmx2g \
-Xmn800m \
-Xss256k \
-XX:MetaspaceSize=128m \
-XX:MaxMetaspaceSize=256m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:+PrintGCDetails \
-Xloggc:/logs/microservice-gc.log \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/dumps/ \
-jar microservice-app.jar低延迟应用配置(JDK 11+)
bash
java -server \
-Xms8g -Xmx8g \
-XX:+UseZGC \
-XX:ZCollectionInterval=120 \
-XX:ZFragmentationLimit=10 \
-Xlog:gc*:file=gc.log:time,uptime:filecount=10,filesize=100M \
-XX:+HeapDumpOnOutOfMemoryError \
-jar low-latency-app.jarGC调优最佳实践
mermaid
graph TB
A["GC调优原则"] --> B["1. 明确性能目标"]
A --> C["2. 基线测试"]
A --> D["3. 逐步调整"]
A --> E["4. 监控验证"]
B --> B1["吞吐量优先<br/>停顿时间优先<br/>内存占用优先"]
C --> C1["记录默认参数性能<br/>建立对比基准"]
D --> D1["单次只调整一个参数<br/>观察影响后再调整下一个"]
E --> E1["持续监控GC日志<br/>验证调优效果"]
style A fill:#5C6BC0,stroke:#3949AB,stroke-width:3px,color:#fff
style B fill:#81C784,stroke:#388E3C,stroke-width:2px,color:#1B5E20
style C fill:#64B5F6,stroke:#1976D2,stroke-width:2px,color:#0D47A1
style D fill:#FFB74D,stroke:#F57C00,stroke-width:2px,color:#E65100
style E fill:#CE93D8,stroke:#7B1FA2,stroke-width:2px,color:#4A148C收集器选型建议
| 场景 | 推荐收集器 | 原因 |
|---|---|---|
| 通用服务端应用 | G1 | 平衡吞吐和延迟 |
| 大数据批处理 | Parallel | 最大吞吐量 |
| 延迟敏感应用 | ZGC/Shenandoah | 毫秒级停顿 |
| 小内存应用 | Serial | 简单高效 |
| 超大堆应用 | ZGC | 处理TB级堆 |
核心调优建议
- 务必开启GC日志: 详细日志是定位性能问题的关键依据
- 配置OOM自动转储: 发生OOM时自动生成堆转储文件便于事后分析
- 选择合适的GC: 根据应用特征选择垃圾收集器
- 避免过度优化: 参数调整应基于实际监控数据,避免凭感觉调整
- 定期review GC日志: 及时发现潜在问题
垃圾收集器的选择和配置需要根据应用特点和性能目标来决定。没有万能的配置,只有最适合当前应用场景的配置。通过持续监控和调优,可以找到最佳的GC配置方案。
更新: 2025-12-06 15:43:25
原文: https://www.yuque.com/u22210564/zoxfmt/sufyeawvxfui866q