Skip to content

JVM的垃圾回收机制

JVM 的垃圾回收机制(Garbage Collection, GC)是自动管理堆内存的进程,通过识别和回收不再使用的对象,释放内存空间,防止内存泄漏。它基于可达性分析判断对象存活,结合分代回收策略(如新生代、老年代),使用多种算法(如标记-清除、复制)优化性能。


1. 垃圾回收机制概述

作用

  • 自动回收堆中无引用对象,释放内存。
  • 避免手动管理(如 C 的 free())。

管理区域

  • :GC 主要目标(对象和数组)。
  • 方法区:回收废弃常量和无用类(较少)。

核心步骤

  1. 标记:识别哪些对象是垃圾。
  2. 回收:清除垃圾,整理内存(可选)。

2. 如何判断对象可回收

(1) 可达性分析

  • 原理
  • GC Roots 开始,追踪引用链。
  • 未被引用的对象视为垃圾。
  • GC Roots
  • 虚拟机栈中的局部变量。
  • 方法区中的静态变量、常量。
  • 本地方法栈中的 JNI 引用。
  • 示例
Object a = new Object(); // 可达
a = null; // 不可达,下次 GC 回收

(2) 引用类型

  • 强引用Object o = new Object(),不回收。
  • 软引用SoftReference,内存不足时回收。
  • 弱引用WeakReference,下次 GC 回收。
  • 虚引用PhantomReference,跟踪回收状态。

(3) Finalize 方法

  • 对象不可达时,可执行 finalize() 自救。
  • 仅执行一次,若仍不可达则回收。
@Override
protected void finalize() throws Throwable {
    System.out.println("Self save");
    this.ref = this; // 自救
}

3. 分代回收策略

堆分代

  • 新生代(Young Generation):
  • Eden:新对象创建。
  • Survivor(From、To):存活对象。
  • 老年代(Old Generation):
  • 长期存活对象。
  • 比例:默认新生代:老年代 = 1:2。

分代假设

  • 弱分代假设:大部分对象朝生夕死。
  • 强分代假设:存活越久越难回收。

GC 类型

  • Minor GC
  • 清理新生代,触发频繁,速度快。
  • Major GC / Full GC
  • 清理整个堆,耗时长,含老年代。

4. 垃圾回收算法

(1) 标记-清除(Mark-Sweep)

  • 过程
  • 标记可达对象,清除未标记对象。
  • 优点:简单。
  • 缺点:内存碎片。

(2) 复制(Copying)

  • 过程
  • 将存活对象复制到另一区域,清空原区域。
  • 优点:无碎片,适合新生代。
  • 缺点:内存利用率低(一半空闲)。

(3) 标记-整理(Mark-Compact)

  • 过程
  • 标记后,将存活对象移到一端,清除剩余。
  • 优点:无碎片,适合老年代。
  • 缺点:整理耗时。

(4) 分代收集

  • 新生代:复制算法(Eden -> Survivor)。
  • 老年代:标记-清除或标记-整理。

5. 垃圾回收器

常见回收器(HotSpot JVM)

  • Serial:单线程,适合小应用。
  • Parallel:多线程并行,吞吐量高。
  • CMS(Concurrent Mark Sweep)
  • 并发标记-清除,低停顿。
  • 缺点:碎片多。
  • G1(Garbage First)
  • 分区管理,预测停顿时间。
  • 适合大堆,低延迟。
  • ZGC / Shenandoah(JDK 11+):
  • 超低停顿(<10ms),适合超大堆。

执行过程(G1 示例)

  1. 初始标记(STW):标记 GC Roots。
  2. 并发标记:追踪引用。
  3. 最终标记(STW):修正标记。
  4. 筛选回收:清理垃圾区域。

6. 触发条件

  • Minor GC:Eden 满。
  • Full GC
  • 老年代满。
  • 元空间不足(-XX:MaxMetaspaceSize)。
  • System.gc()(建议性)。

延伸与面试角度

  • STW(Stop The World)
  • GC 时暂停应用线程。
  • CMS、G1 减少 STW。
  • 调优参数
  • -Xms-Xmx:堆大小。
  • -XX:+UseG1GC:指定 G1。
  • -XX:MaxGCPauseMillis:目标停顿。
  • 内存泄漏
  • 对象长期可达(如静态集合)。
  • 面试点
  • 问“算法”时,提标记-清除 vs 复制。
  • 问“回收器”时,提 G1 和 CMS。

示例

public class GCTest {
    public static void main(String[] args) {
        List<Object> list = new ArrayList<>();
        while (true) {
            list.add(new Object()); // 触发 GC
        }
    }
}

总结

JVM 垃圾回收通过可达性分析标记垃圾,分代策略(新生代复制,老年代标记-整理)回收内存,使用回收器(如 G1)优化性能。面试时,可画堆分代图或提调优参数,展示理解深度。