Java垃圾回收器

Java垃圾回收器

概述

垃圾回收(Garbage Collection,GC)是Java虚拟机(JVM)自动管理内存的机制。它负责回收不再被程序使用的对象所占用的内存空间,避免内存泄漏和内存溢出。

垃圾回收基础

内存区域

  • 堆内存(Heap):存储对象实例,GC主要工作区域
    • 新生代(Young Generation)
      • Eden区
      • Survivor区(S0、S1)
    • 老年代(Old Generation)
  • 方法区(Method Area):存储类信息、常量池等
  • 程序计数器、虚拟机栈、本地方法栈:不需要GC

对象生命周期

  1. 对象在Eden区创建
  2. Eden区满时触发Minor GC
  3. 存活对象移到Survivor区
  4. 经过多次GC后,长期存活的对象晋升到老年代
  5. 老年代满时触发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)

  • 特点:并发收集,低延迟
  • 适用场景:响应时间敏感的应用
  • 工作过程
    1. 初始标记(STW)
    2. 并发标记
    3. 重新标记(STW)
    4. 并发清除
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

最佳实践

  1. 监控GC性能:定期检查GC日志和监控指标
  2. 避免内存泄漏:及时释放不需要的对象引用
  3. 合理使用缓存:避免缓存过大导致GC压力
  4. 选择合适的数据结构:考虑内存占用和GC影响
  5. 分代假说优化:短生命周期对象在新生代快速回收
  6. 避免大对象:大对象直接进入老年代,影响GC效率

总结

选择合适的垃圾回收器和调优参数对Java应用的性能至关重要。需要根据应用的特点(吞吐量优先还是延迟优先)、硬件环境和业务需求来选择最适合的GC策略。同时,持续监控和调优是保证应用性能的关键。