Java垃圾回收器
Java垃圾回收器
概述
垃圾回收(Garbage Collection,GC)是Java虚拟机(JVM)自动管理内存的机制。它负责回收不再被程序使用的对象所占用的内存空间,避免内存泄漏和内存溢出。
垃圾回收基础
内存区域
- 堆内存(Heap):存储对象实例,GC主要工作区域
- 新生代(Young Generation)
- Eden区
- Survivor区(S0、S1)
- 老年代(Old Generation)
- 新生代(Young Generation)
- 方法区(Method Area):存储类信息、常量池等
- 程序计数器、虚拟机栈、本地方法栈:不需要GC
对象生命周期
- 对象在Eden区创建
- Eden区满时触发Minor GC
- 存活对象移到Survivor区
- 经过多次GC后,长期存活的对象晋升到老年代
- 老年代满时触发Major GC或Full GC
GC算法
标记-清除算法(Mark-Sweep)
- 过程:标记需要回收的对象,然后清除
- 优点:实现简单
- 缺点:产生内存碎片,效率不高
复制算法(Copying)
- 过程:将内存分为两块,每次只使用一块,GC时将存活对象复制到另一块
- 优点:效率高,无内存碎片
- 缺点:内存利用率低(只能使用一半)
标记-整理算法(Mark-Compact)
- 过程:标记存活对象,然后将其向一端移动,清理边界外的内存
- 优点:无内存碎片,内存利用率高
- 缺点:移动对象成本较高
分代收集算法
- 新生代:使用复制算法(对象存活率低)
- 老年代:使用标记-清除或标记-整理算法(对象存活率高)
垃圾回收器类型
Serial GC
- 特点:单线程收集器
- 适用场景:单核CPU、小型应用
- 新生代:Serial收集器
- 老年代:Serial Old收集器
bash
# 启用参数
-XX:+UseSerialGC
# 启用参数
-XX:+UseSerialGC
Parallel GC(默认)
- 特点:多线程并行收集
- 适用场景:多核CPU、吞吐量优先的应用
- 新生代:Parallel Scavenge收集器
- 老年代:Parallel Old收集器
bash
# 启用参数
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:ParallelGCThreads=4 # 设置并行线程数
# 启用参数
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:ParallelGCThreads=4 # 设置并行线程数
CMS GC(Concurrent Mark Sweep)
- 特点:并发收集,低延迟
- 适用场景:响应时间敏感的应用
- 工作过程:
- 初始标记(STW)
- 并发标记
- 重新标记(STW)
- 并发清除
bash
# 启用参数
-XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode # 增量模式
-XX:CMSInitiatingOccupancyFraction=70 # 触发阈值
# 启用参数
-XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode # 增量模式
-XX:CMSInitiatingOccupancyFraction=70 # 触发阈值
G1 GC(Garbage First)
- 特点:低延迟、可预测的停顿时间
- 适用场景:大堆内存(>4GB)、低延迟要求
- 工作原理:
- 将堆分为多个Region
- 优先回收垃圾最多的Region
- 并发标记和并发回收
bash
# 启用参数
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200 # 最大停顿时间目标
-XX:G1HeapRegionSize=16m # Region大小
# 启用参数
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200 # 最大停顿时间目标
-XX:G1HeapRegionSize=16m # Region大小
ZGC(Z Garbage Collector)
- 特点:超低延迟(<10ms)
- 适用场景:对延迟极其敏感的应用
- 支持版本:JDK 11+(实验性),JDK 15+(生产可用)
bash
# 启用参数(JDK 11-14)
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
# 启用参数(JDK 15+)
-XX:+UseZGC
# 启用参数(JDK 11-14)
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
# 启用参数(JDK 15+)
-XX:+UseZGC
Shenandoah GC
- 特点:低延迟、并发收集
- 适用场景:大堆内存、低延迟要求
- 支持版本:OpenJDK 12+
bash
# 启用参数
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
# 启用参数
-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC
垃圾回收器对比
收集器 | 类型 | 目标 | 停顿时间 | 吞吐量 | 适用场景 |
---|---|---|---|---|---|
Serial | 串行 | 简单 | 较长 | 一般 | 单核、小应用 |
Parallel | 并行 | 吞吐量 | 较长 | 高 | 多核、后台任务 |
CMS | 并发 | 低延迟 | 短 | 一般 | 响应敏感应用 |
G1 | 并发 | 平衡 | 可控 | 较高 | 大堆、平衡需求 |
ZGC | 并发 | 超低延迟 | 极短 | 较高 | 延迟敏感应用 |
Shenandoah | 并发 | 低延迟 | 短 | 较高 | 大堆、低延迟 |
GC调优
监控工具
bash
# jstat - 查看GC统计信息
jstat -gc <pid> 1s
# jmap - 查看堆内存使用情况
jmap -heap <pid>
# jcmd - 执行GC
jcmd <pid> GC.run
# jstat - 查看GC统计信息
jstat -gc <pid> 1s
# jmap - 查看堆内存使用情况
jmap -heap <pid>
# jcmd - 执行GC
jcmd <pid> GC.run
常用JVM参数
bash
# 堆内存设置
-Xms2g -Xmx4g # 初始堆大小和最大堆大小
# 新生代设置
-Xmn1g # 新生代大小
-XX:NewRatio=3 # 老年代与新生代比例
-XX:SurvivorRatio=8 # Eden与Survivor比例
# GC日志
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
# 内存溢出时dump堆
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump
# 堆内存设置
-Xms2g -Xmx4g # 初始堆大小和最大堆大小
# 新生代设置
-Xmn1g # 新生代大小
-XX:NewRatio=3 # 老年代与新生代比例
-XX:SurvivorRatio=8 # Eden与Survivor比例
# GC日志
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
# 内存溢出时dump堆
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump
调优策略
1. 选择合适的收集器
- CPU密集型应用:Parallel GC
- 响应时间敏感:G1 GC或CMS GC
- 超大堆内存:ZGC或Shenandoah GC
2. 合理设置堆大小
bash
# 一般建议
-Xms和-Xmx设置为相同值,避免动态扩容
堆大小设置为系统内存的70-80%
# 一般建议
-Xms和-Xmx设置为相同值,避免动态扩容
堆大小设置为系统内存的70-80%
3. 优化新生代配置
bash
# 新生代过小:频繁Minor GC
# 新生代过大:Minor GC时间长
# 建议新生代占堆内存的25-50%
# 新生代过小:频繁Minor GC
# 新生代过大:Minor GC时间长
# 建议新生代占堆内存的25-50%
4. 减少对象创建
- 使用对象池
- 避免在循环中创建对象
- 使用StringBuilder代替String拼接
实际案例
高吞吐量应用调优
bash
# 适用于批处理、数据分析等场景
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:ParallelGCThreads=8
-Xms8g -Xmx8g
-XX:NewRatio=2
# 适用于批处理、数据分析等场景
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:ParallelGCThreads=8
-Xms8g -Xmx8g
-XX:NewRatio=2
低延迟应用调优
bash
# 适用于Web应用、在线服务等场景
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-Xms4g -Xmx4g
-XX:G1HeapRegionSize=16m
# 适用于Web应用、在线服务等场景
-XX:+UseG1GC
-XX:MaxGCPauseMillis=100
-Xms4g -Xmx4g
-XX:G1HeapRegionSize=16m
超大堆应用调优
bash
# 适用于大数据处理、缓存服务等场景
-XX:+UseZGC
-Xms32g -Xmx32g
-XX:+UnlockExperimentalVMOptions
# 适用于大数据处理、缓存服务等场景
-XX:+UseZGC
-Xms32g -Xmx32g
-XX:+UnlockExperimentalVMOptions
最佳实践
- 监控GC性能:定期检查GC日志和监控指标
- 避免内存泄漏:及时释放不需要的对象引用
- 合理使用缓存:避免缓存过大导致GC压力
- 选择合适的数据结构:考虑内存占用和GC影响
- 分代假说优化:短生命周期对象在新生代快速回收
- 避免大对象:大对象直接进入老年代,影响GC效率
总结
选择合适的垃圾回收器和调优参数对Java应用的性能至关重要。需要根据应用的特点(吞吐量优先还是延迟优先)、硬件环境和业务需求来选择最适合的GC策略。同时,持续监控和调优是保证应用性能的关键。