YGC和FGC

517 阅读4分钟

在Java虚拟机(JVM)中,垃圾回收(GC)分为年轻代垃圾回收(Young GC, YGC)和老年代垃圾回收(Full GC, FGC)。它们的工作方式、触发条件和对应用性能的影响都有所不同。以下是对YGC和FGC的详细解释:

年轻代垃圾回收(Young GC, YGC)

工作原理

  • 年轻代:JVM堆内存分为年轻代(Young Generation)和老年代(Old Generation)。年轻代又细分为Eden区和两个Survivor区(S0和S1)。
  • 对象分配:大多数新对象分配在Eden区。当Eden区填满时,会触发YGC。
  • 垃圾回收算法:YGC通常使用复制算法(Copying Algorithm),将存活的对象从Eden区和一个Survivor区复制到另一个Survivor区(或者直接晋升到老年代)。
  • 效率:YGC效率较高,因为大多数新创建的对象生命周期较短,很快就会被回收。

触发条件

  • Eden区满:当Eden区填满时,会触发一次YGC。
  • Survivor区满:在某些情况下,当Survivor区无法容纳所有存活对象时,也可能触发YGC。

对应用的影响

  • 停顿时间(STW):YGC会导致短时间的Stop-The-World(STW)事件,但由于年轻代较小且大多数对象可以快速回收,停顿时间通常在几十毫秒内。

老年代垃圾回收(Full GC, FGC)

工作原理

  • 老年代:老年代存放从年轻代晋升过来的长期存活对象。
  • 垃圾回收算法:FGC通常使用标记-清除(Mark-Sweep)或标记-整理(Mark-Compact)算法。G1 GC则使用混合回收(Mixed GC),同时回收老年代和年轻代的一部分区域。
  • 复杂性:FGC涉及整个堆内存的扫描和整理,因此比YGC复杂,停顿时间较长。

触发条件

  • 老年代满:当老年代无法容纳更多对象时,触发FGC。
  • 永久代或元空间满:在JDK 8及之前,如果永久代(PermGen)满了会触发FGC。在JDK 8以后,元空间(Metaspace)满了也可能触发FGC。
  • 显式调用:调用System.gc()或其他显式GC请求可能触发FGC。
  • 其他条件:一些JVM配置和内存使用模式也可能触发FGC,例如内存分配失败。

对应用的影响

  • 停顿时间(STW):FGC会导致较长时间的Stop-The-World事件,停顿时间从几百毫秒到几秒不等,具体取决于堆内存大小和对象复杂性。
  • 性能影响:频繁的FGC对应用性能影响较大,尤其是对响应时间敏感的应用。

优化和调优建议

减少YGC频率和停顿时间

  1. 增加年轻代大小:适当增加年轻代的大小可以减少YGC频率。
    -XX:NewSize=512m -XX:MaxNewSize=512m
    
  2. 调整Survivor区比例:调整Survivor区的比例以优化对象晋升和存活。
    -XX:SurvivorRatio=8
    
  3. 减少短期对象创建:优化代码,减少短生命周期对象的创建。

减少FGC频率和停顿时间

  1. 增加堆内存大小:增加整个堆内存大小可以减少FGC频率。
    -Xms8g -Xmx8g
    
  2. 使用G1 GC或其他低停顿GC:选择G1 GC、ZGC或Shenandoah GC来减少FGC停顿时间。
    -XX:+UseG1GC
    
  3. 避免显式调用System.gc():除非必要,避免显式调用System.gc(),可以通过设置禁止显式GC。
    -XX:+DisableExplicitGC
    
  4. 优化老年代对象:分析和优化老年代对象,减少不必要的对象晋升。

示例配置

使用G1 GC的配置(适用于低停顿、高吞吐)

java -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:InitiatingHeapOccupancyPercent=45 \
     -XX:G1HeapRegionSize=8m \
     -XX:ParallelGCThreads=4 \
     -XX:ConcGCThreads=2 \
     -Xms8g -Xmx8g \
     -jar your-application.jar

监控和分析

使用监控工具(如Prometheus + Grafana、JVisualVM、YourKit、JProfiler等)实时监控YGC和FGC的频率和时长,通过分析GC日志(启用GC日志)获取详细信息。

启用GC日志

java -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -jar your-application.jar

通过上述方法,可以有效监控和优化YGC和FGC行为,提高JVM应用的性能和稳定性。