Java 垃圾收集机制

垃圾收集的基本概念

垃圾收集(Garbage Collection, GC) 是 JVM 自动管理内存的机制,负责回收不再使用的对象所占用的内存。

关键概念

  • 垃圾对象:不再被任何引用指向的对象

  • GC Roots:始终可达的对象,作为引用链的起点

  • Stop-the-World:GC 执行时暂停所有应用线程

内存分代模型

JVM 将堆内存分为三个主要区域:

1. 年轻代 (Young Generation)

  • Eden区:新创建的对象首先分配在这里

  • Survivor区 (S0, S1):经历 Minor GC 后存活的对象在这里交换

2. 老年代 (Old Generation)

  • 长期存活的对象最终会晋升到这里

  • 需要 Major GC/Full GC 来清理

3. 元空间 (Metaspace) - JDK 8+

  • 存储类元数据、方法信息等

  • 替代了之前的永久代 (PermGen)

垃圾收集算法

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

// 概念性代码
public class MarkSweep {
    public void garbageCollect() {
        // 阶段1: 标记 - 找出所有存活对象
        markFromRoots();
        // 阶段2: 清除 - 回收未标记对象的内存
        sweep();
    }
    private void markFromRoots() {
        // 从GC Roots开始遍历所有可达对象并标记
    }
    private void sweep() {
        // 遍历堆内存,回收未标记对象
    }
}

2. 复制算法 (Copying)

  • 将内存分为两块,只使用其中一块。GC 时将存活对象复制到另一块,然后清空当前块。

  • 用于年轻代的 Survivor 区。

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

  • 先标记所有存活对象。然后将存活对象向一端移动,清理边界以外的内存。

  • 用于老年代。

主要的垃圾收集器

1. Serial GC

  • 单线程收集器。适合客户端应用、小内存场景

 

-XX:+UseSerialGC

 

2. Parallel GC (吞吐量优先)

  • 多线程并行收集。JDK 8 默认收集器

-XX:+UseParallelGC

3. CMS (Concurrent Mark Sweep)

  • 尽量减少停顿时间。与应用程序并发执行

-XX:+UseConcMarkSweepGC

4. G1 (Garbage First) - JDK 9+ 默认

// G1 的堆内存布局
public class G1Layout {
    // 将堆划分为多个等大小的Region (1MB-32MB)
    // 不再固定分代大小,动态分配
    // 优先回收垃圾最多的Region (Garbage First)
}

5. ZGC (低延迟)

  • 目标:停顿时间不超过10ms。支持TB级别堆内存

-XX:+UseZGC

6. Shenandoah

  • 类似ZGC的低延迟收集器。与应用程序并发执行

-XX:+UseShenandoahGC

GC 触发时机

1. Minor GC

  • 当Eden区满时触发。只收集年轻代。频率高,停顿时间短

2. Major GC / Full GC

  • 当老年代满时触发。收集整个堆(年轻代 + 老年代)。频率低,停顿时间长

对象生命周期

public class ObjectLifecycle {
    public void demonstrate() {
        // 1. 对象在Eden区创建
        Object obj1 = new Object();
        
        // 2. 经历Minor GC后,如果存活则进入Survivor区
        // 每经历一次Minor GC,年龄+1
        
        // 3. 当年龄达到阈值(默认15),晋升到老年代
        for (int i = 0; i < 15; i++) {
            System.gc(); // 模拟多次GC
        }
        
        // 4. 最终在Full GC时被回收(如果没有引用)
        obj1 = null; // 使对象成为垃圾
        System.gc(); // 建议JVM执行GC
    }
}

常见的 GC 调优参数

# 设置堆大小
-Xms512m -Xmx2g

# 设置年轻代大小
-XX:NewRatio=2           # 老年代:年轻代 = 2:1
-XX:NewSize=256m -XX:MaxNewSize=512m

# 设置Survivor区比例
-XX:SurvivorRatio=8      # Eden:Survivor = 8:1:1

# 选择GC算法
-XX:+UseG1GC
-XX:+UseParallelGC
-XX:+UseZGC

# GC日志配置
-Xlog:gc*:file=gc.log:time,uptime,level,tags
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps

最佳实践

  1. 及时释放引用:对象不再使用时设为null

  2. 避免大对象:大对象直接进入老年代

  3. 合理使用集合:及时清理不再需要的集合数据

  4. 使用局部变量:方法结束后自动释放

  5. 谨慎使用静态集合:容易导致内存泄漏

监控工具

  • jstat:监控GC统计信息

  • jmap:堆内存分析

  • VisualVM:图形化监控

  • GC日志:分析GC行为和性能

posted @ 2025-11-16 16:42  YukiRinLL  阅读(0)  评论(0)    收藏  举报