JAVA中JVM一次 GC的 流程

发布于:2025-03-29 ⋅ 阅读:(27) ⋅ 点赞:(0)

一、JVM 中一次完整的 GC 流程(以分代回收为例)

JVM 的垃圾回收(GC)流程依赖于分代收集机制,不同区域(新生代、老年代)采用不同的回收策略。以下是典型的完整 GC 流程(以 Parallel Scavenge + Parallel Old 组合为例):


1. Minor GC(新生代回收)
  • 触发条件

    • 新生代(Eden 区)空间不足,无法分配新对象。

  • 流程

    1. 标记存活对象
      从 GC Roots(如线程栈、静态变量等)出发,标记所有存活对象。

    2. 复制存活对象
      将 Eden 区和当前使用的 Survivor(From 区)中的存活对象复制到另一个 Survivor(To 区),并清空 Eden 和 From 区。

    3. 年龄增长
      Survivor 区中存活对象的年龄(Age)增加 1。

    4. 晋升老年代
      若对象年龄达到阈值(默认 15),或 Survivor 区空间不足,存活对象会晋升到老年代。


2. Major GC / Full GC(老年代回收)
  • 触发条件

    • 老年代空间不足(如晋升失败)。

    • 显式调用 System.gc()(不推荐)。

    • 元数据区(Metaspace)空间不足。

  • 流程(以 Parallel Old 为例):

    1. 标记存活对象
      标记老年代中所有存活对象。

    2. 压缩整理(Compaction)
      将所有存活对象向老年代一端移动,清理碎片化空间。

    3. 更新引用
      修正所有指向被移动对象的引用地址。


二、对象晋升到老年代的条件

对象从新生代晋升到老年代的条件如下:

  1. 年龄阈值

    • 对象在 Survivor 区经历的 Minor GC 次数达到阈值(默认 -XX:MaxTenuringThreshold=15)。

  2. 动态年龄判断

    • 如果 Survivor 区中某年龄段的对象总大小超过 Survivor 区的一半,则所有大于等于该年龄的对象直接晋升。

  3. 大对象直接进入老年代

    • 若对象大小超过 -XX:PretenureSizeThreshold(默认 0,需手动设置),直接分配到老年代。

  4. Survivor 区空间不足

    • 当 Survivor 区无法容纳 Minor GC 后的存活对象时,直接晋升到老年代。


三、重要的 JVM 参数

以下是常见的 JVM 参数分类说明:


1. 堆内存相关
参数 作用 示例
-Xms 初始堆大小 -Xms512m(堆初始 512MB)
-Xmx 最大堆大小 -Xmx4g(堆最大 4GB)
-Xmn 新生代大小 -Xmn1g(新生代 1GB)
-XX:NewRatio 新生代与老年代比例 -XX:NewRatio=2(老年代:新生代=2:1)
-XX:SurvivorRatio Eden 区与 Survivor 区比例 -XX:SurvivorRatio=8(Eden:Survivor=8:1:1)

2. GC 行为控制
参数 作用 示例
-XX:+UseSerialGC 使用串行回收器(单线程) (适合低配机器)
-XX:+UseParallelGC 使用 Parallel Scavenge 回收器 (默认并行回收新生代)
-XX:+UseConcMarkSweepGC 使用 CMS 回收器(已废弃) (低停顿,Java 8 前常用)
-XX:+UseG1GC 使用 G1 回收器 (分区回收,Java 9+ 默认)
-XX:MaxTenuringThreshold 对象晋升年龄阈值 -XX:MaxTenuringThreshold=15
-XX:PretenureSizeThreshold 大对象直接进入老年代的阈值 -XX:PretenureSizeThreshold=2m

3. GC 日志与监控
参数 作用 示例
-XX:+PrintGCDetails 打印 GC 详细信息 (需配合日志分析工具)
-XX:+PrintGCDateStamps 输出 GC 时间戳
-Xloggc:<path> 指定 GC 日志文件路径 -Xloggc:/logs/gc.log
-XX:+HeapDumpOnOutOfMemoryError OOM 时生成堆转储 (用于分析内存泄漏)

4. 元数据区(Metaspace)
参数 作用 示例
-XX:MetaspaceSize 初始元数据区大小 -XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize 元数据区最大大小 -XX:MaxMetaspaceSize=256m

四、示例参数配置

# 启动一个 Java 应用,配置堆大小和 G1 回收器
java -Xms2g -Xmx2g \
     -XX:+UseG1GC \
     -XX:MaxGCPauseMillis=200 \
     -XX:MetaspaceSize=128m \
     -XX:MaxMetaspaceSize=256m \
     -Xloggc:/logs/gc.log \
     -jar myapp.jar

五、总结

  • GC 流程:分代回收通过 Minor GC 和 Full GC 协作完成,新生代用复制算法,老年代用标记-清除或标记-整理算法。

  • 对象晋升:基于年龄、动态判断、空间不足等因素决定是否晋升到老年代。

  • JVM 参数:需根据应用场景(吞吐量优先或低延迟)选择回收器和调整参数,结合监控工具(如 VisualVM、GCViewer)优化配置。