跳转到内容

垃圾收集器(Garbage Collector)

来自代码酷

垃圾收集器(Garbage Collector)[编辑 | 编辑源代码]

垃圾收集器(Garbage Collector,简称 GC)是 Java虚拟机(JVM)的重要组成部分,负责自动管理内存,回收不再使用的对象以释放内存空间。Java 开发者无需手动释放内存,从而避免了内存泄漏和野指针等问题。

1. 垃圾收集的基本概念[编辑 | 编辑源代码]

1.1 什么是垃圾收集?[编辑 | 编辑源代码]

在 Java 中,垃圾收集是指 JVM 自动检测并回收不再被引用的对象所占用的内存。当一个对象不再被任何活动线程或静态变量引用时,它就被视为“垃圾”,可以被回收。

1.2 为什么需要垃圾收集?[编辑 | 编辑源代码]

  • **避免内存泄漏**:自动回收不再使用的对象,防止内存被无效占用。
  • **减少开发负担**:开发者无需手动管理内存,降低代码复杂度。
  • **提高程序稳定性**:减少因内存管理不当导致的程序崩溃。

2. 垃圾收集算法[编辑 | 编辑源代码]

JVM 使用不同的垃圾收集算法来识别和回收垃圾对象。以下是几种常见的算法:

2.1 标记-清除(Mark-Sweep)[编辑 | 编辑源代码]

1. **标记阶段**:遍历所有可达对象,标记为“存活”。 2. **清除阶段**:回收未被标记的对象。

    • 缺点**:产生内存碎片。

2.2 复制(Copying)[编辑 | 编辑源代码]

将内存分为两块,每次只使用其中一块。垃圾回收时,将存活对象复制到另一块内存,然后清空当前块。

    • 优点**:避免内存碎片。
    • 缺点**:内存利用率低(仅 50%)。

2.3 标记-整理(Mark-Compact)[编辑 | 编辑源代码]

1. **标记阶段**:标记所有存活对象。 2. **整理阶段**:将所有存活对象移动到内存的一端,然后清理剩余部分。

    • 优点**:避免碎片,内存利用率高。
    • 缺点**:整理过程耗时较长。

2.4 分代收集(Generational Collection)[编辑 | 编辑源代码]

基于对象的生命周期将内存划分为不同的代(如新生代、老年代),并采用不同的回收策略。

  • **新生代(Young Generation)**:存放新创建的对象,使用复制算法(如 Serial、ParNew、G1)。
  • **老年代(Old Generation)**:存放长期存活的对象,使用标记-清除或标记-整理算法(如 CMS、G1)。

3. JVM 中的垃圾收集器[编辑 | 编辑源代码]

JVM 提供了多种垃圾收集器,适用于不同的应用场景:

3.1 Serial GC[编辑 | 编辑源代码]

  • **特点**:单线程,适用于小型应用或客户端程序。
  • **算法**:新生代(复制),老年代(标记-整理)。
  • **适用场景**:低内存、单核 CPU。

3.2 Parallel GC(吞吐量优先)[编辑 | 编辑源代码]

  • **特点**:多线程并行回收,提高吞吐量。
  • **算法**:新生代(复制),老年代(标记-整理)。
  • **适用场景**:多核 CPU,注重吞吐量的应用(如批处理)。

3.3 CMS(Concurrent Mark-Sweep)[编辑 | 编辑源代码]

  • **特点**:并发标记和清除,减少停顿时间(低延迟)。
  • **算法**:标记-清除(老年代)。
  • **缺点**:内存碎片问题。

3.4 G1(Garbage-First)[编辑 | 编辑源代码]

  • **特点**:分区(Region)收集,兼顾吞吐量和低延迟。
  • **算法**:标记-整理 + 复制(混合)。
  • **适用场景**:大内存、多核服务器(JDK 9+ 默认)。

3.5 ZGC & Shenandoah[编辑 | 编辑源代码]

  • **特点**:超低停顿(<10ms),适用于超大堆内存(TB 级别)。
  • **适用场景**:云原生、实时系统。

4. 代码示例:观察垃圾收集[编辑 | 编辑源代码]

以下代码演示如何手动触发垃圾收集并观察其行为:

  
public class GCDemo {  
    public static void main(String[] args) {  
        // 创建大量临时对象  
        for (int i = 0; i < 100000; i++) {  
            new Object(); // 这些对象很快会被回收  
        }  

        // 手动建议 JVM 执行 GC(不保证立即执行)  
        System.gc();  

        // 查看内存使用情况  
        Runtime runtime = Runtime.getRuntime();  
        long freeMemory = runtime.freeMemory();  
        long totalMemory = runtime.totalMemory();  
        System.out.println("Free Memory: " + freeMemory);  
        System.out.println("Total Memory: " + totalMemory);  
    }  
}
    • 输出示例**:
  
Free Memory: 12345678  
Total Memory: 16777216  

5. 实际应用场景[编辑 | 编辑源代码]

  • **Web 服务器**:使用 G1 或 ZGC 减少 GC 停顿,提高响应速度。
  • **大数据处理**:使用 Parallel GC 最大化吞吐量。
  • **Android 应用**:使用 ART 的并发 GC 减少卡顿。

6. 性能调优建议[编辑 | 编辑源代码]

  • **调整堆大小**:`-Xms`(初始堆)、`-Xmx`(最大堆)。
  • **选择收集器**:如 `-XX:+UseG1GC` 启用 G1。
  • **监控 GC 日志**:使用 `-Xlog:gc*` 分析停顿时间。

7. 总结[编辑 | 编辑源代码]

垃圾收集器是 JVM 内存管理的核心组件,不同的收集器适用于不同的场景。理解其工作原理有助于优化 Java 应用的性能和稳定性。

graph LR A[垃圾收集器] --> B[Serial GC] A --> C[Parallel GC] A --> D[CMS] A --> E[G1] A --> F[ZGC/Shenandoah]